1.进程和线程的区别,说说线程管理。
- 进程:是活动的程序,是一个容器;是系统资源管理的最小单位;切换代价较高
- 线程:是在进程容器中运行,实际工作的代码;是程序执行的最小单位;切换代价低
- 单线程:一个进程内只有一个线程;一个进程的数据通常加载在同一内存中!
- 多线程:一个进程内有多个线程;多个线程通常共享同一内存中的数据!
- 线程与进程切换的区别:线程完全共享相同的地址空间,切换代价低;进程的地址空间是独立的,切换代价高
- 进程与线程之间的区别:
简而言之,一个程序至少有一个进程,一个进程至少有一个线程.
线程的划分尺度小于进程,使得多线程程序的并发性高。
另外,进程在执行过程中拥有独立的内存单元,而多个线程共享内存,从而极大地提高了程序的运行效率。
线程在执行过程中与进程还是有区别的。每个独立的线程有一个程序运行的入口、顺序执行序列和程序的出口。但是线程不能够独立执行,必须依存在应用程序中,由应用程序提供多个线程执行控制。
从逻辑角度来看,多线程的意义在于一个应用程序中,有多个执行部分可以同时执行。但操作系统并没有将多个线程看做多个独立的应用,来实现进程的调度和管理以及资源分配。这就是进程和线程的重要区别。进程是具有一定独立功能的程序关于某个数据集合上的一次运行活动,进程是系统进行资源分配和调度的一个独立单位.
线程是进程的一个实体,是CPU调度和分派的基本单位,它是比进程更小的能独立运行的基本单位.线程自己基本上不拥有系统资源,只拥有一点在运行中必不可少的资源(如程序计数器,一组寄存器和栈),但是它可与同属一个进程的其他的线程共享进程所拥有的全部资源.
一个线程可以创建和撤销另一个线程;同一个进程中的多个线程之间可以并发执行.进程和线程的主要差别在于它们是不同的操作系统资源管理方式。进程有独立的地址空间,一个进程崩溃后,在保护模式 下不会对其它进程产生影响,而线程只是一个进程中的不同执行路径。线程有自己的堆栈和局部变量,但线程之间没有单独的地址空间,一个线程死掉就等于整个进 程死掉,所以多进程的程序要比多线程的程序健壮,但在进程切换时,耗费资源较大,效率要差一些。但对于一些要求同时进行并且又要共享某些变量的并发操作, 只能用线程,不能用进程。
- 线程的好处
(1)易于调度。
(2)提高并发性。通过线程可方便有效地实现并发性。进程可创建多个线程来执行同一程序的不同部分。
(3)开销少。创建线程比创建进程要快,所需开销很少。。
(4)利于充分发挥多处理器的功能。通过创建多线程进程(即一个进程可具有两个或更多个线程),每个线程在一个处理器上运行,从而实现应用程序的并发性,使每个处理器都得到充分运行。
2.简述MVC。
MVC是Model-VIew-Controller,就是模型-视图-控制器。即Model,View,Controller。
Model = 你的程序是什么,就是你的程序将要实现的功能,或者是它所能干的事情;Controller = 如何使你的模型呈现给用户(程序逻辑),是连接M和V的桥梁;View = 在屏幕上你所看到的,你在屏幕上看到的组件都可以归类为View。
MVC可以帮助确保帮助实现程序最大程度的可重用性。各MVC元素彼此独立运作,通过分开这些元素,可以构建可维护,可独立更新的程序组建。
3.简述KVO和KVC。
KVO,即:Key-Value Observing,它提供一种机制,当指定的对象的属性被修改后,则对象就会接受到通知。简单的说就是每次指定的被观察的对象的属性被修改后,KVO就会自动通知相应的观察者了。
KVC是KeyValueCoding的简称,它是一种可以直接通过字符串的名字(key)来访问类属性(实例变量)的机制。而不是通过调用Setter、Getter方法访问。
MVC模型中,数据库(dataModal)发生变化时,引起view改变,用这种方式实现非常方便,kvc 常和 kvo 一起使用
4. 编写代码完成提取视图(custom)的当前显示内容为图像,并保存到相册中。
UIGraphicsBeginImageContext(currentView.bounds.size); //currentView当前的view //1.创建上下文,告知要通过上下文绘制图片,并且指定要绘制的图片的尺寸
[currentView.layer renderInContext:UIGraphicsGetCurrentContext()]; //2.对视图来进行绘制,只不过要对视图的layer层进行绘制,将绘制内容写入到创建的上下文中
UIImage *viewImage = UIGraphicsGetImageFromCurrentImageContext(); //3.从上下文中取出刚才绘制的图片。
UIGraphicsEndImageContext(); //4.结束上下文绘制
UIImageWriteToSavedPhotosAlbum(viewImage, nil, nil, nil); //5.将获取到的图片保存到相册
UIImageWriteToSavedPhotosAlbum([custom image], nil, nil,nil);
5.描述视图控制器的两层循环和每个方法的作用。
运行APP —> 载入视图 —> 调用viewDidLoad方法 —> 调用viewWillAppear方法 —> 调用viewDidAppear方法 —> 正常运行
释放对象所有权 <— 调用viewDidUnload <— 收到内存警告 <— 调用viewDidDisappear <— 调用viewWillDisappear <— APP需要调用另一个view
当我们创建一个UIViewController类的对象时,通常系统会生成几个默认的方法,这些方法大多与视图的调用有关,但是在视图调用时,这些方法的调用顺序如何,需要整理下。
通常上述方法包括如下几种,这些方法都是UIViewController类的方法:
- (void)viewDidLoad;
- (void)viewDidUnload;
- (void)viewWillAppear:(BOOL)animated;
- (void)viewDidAppear:(BOOL)animated;
- (void)viewWillDisappear:(BOOL)animated;
- (void)viewDidDisappear:(BOOL)animated;
下面介绍下APP在运行时的调用顺序。
1)- (void)viewDidLoad;
一个APP在载入时会先通过调用loadView方法或者载入IB中创建的初始界面的方法,将视图载入到内存中。然后会调用viewDidLoad方法来进行进一步的设置。通常,我们对于各种初始数据的载入,初始设定等很多内容,都会在这个方法中实现,所以这个方法是一个很常用,很重要的方法。
但是要注意,这个方法只会在APP刚开始加载的时候调用一次,以后都不会再调用它了,所以只能用来做初始设置。
2) - (void)viewDidUnload;
在内存足够的情况下,软件的视图通常会一直保存在内存中,但是如果内存不够,一些没有正在显示的viewcontroller就会收到内存不够的警告,然 后就会释放自己拥有的视图,以达到释放内存的目的。但是系统只会释放内存,并不会释放对象的所有权,所以通常我们需要在这里将不需要在内存中保留的对象释 放所有权,也就是将其指针置为nil。
这个方法通常并不会在视图变换的时候被调用,而只会在系统退出或者收到内存警告的时候才会被调用。但是由于我们需要保证在收到内存警告的时候能够对其作出反应,所以这个方法通常我们都需要去实现。
另外,即使在设备上按了Home键之后,系统也不一定会调用这个方法,因为IOS4之后,系统允许将APP在后台挂起,并将其继续滞留在内存中,因此,viewcontroller并不会调用这个方法来清除内存。
3)- (void)viewWillAppear:(BOOL)animated;
系统在载入所有数据后,将会在屏幕上显示视图,这时会先调用这个方法。通常我们会利用这个方法,对即将显示的视图做进一步的设置。例如,我们可以利用这个方法来设置设备不同方向时该如何显示。
另外一方面,当APP有多个视图时,在视图间切换时,并不会再次载入viewDidLoad方法,所以如果在调入视图时,需要对数据做更新,就只能在这个方法内实现了。所以这个方法也非常常用。
4) - (void)viewDidAppear:(BOOL)animated;
有时候,由于一些特殊的原因,我们不能在viewWillApper方法里,对视图进行更新。那么可以重写这个方法,在这里对正在显示的视图进行进一步的设置。
5) - (void)viewWillDisappear:(BOOL)animated;
在视图变换时,当前视图在即将被移除、或者被覆盖时,会调用这个方法进行一些善后的处理和设置。
由于在IOS4之后,系统允许将APP在后台挂起,所以在按了Home键之后,系统并不会调用这个方法,因为就这个APP本身而言,APP显示的view,仍是挂起时候的view,所以并不会调用这个方法。
6) - (void)viewDidDisappear:(BOOL)animated;
我们可以重写这个方法,对已经消失,或者被覆盖,或者已经隐藏了的视图做一些其他操作。
6.使用Block变量,完成对NSArray实例对象array{@"abc",@"bcd",@"123",@"9987",} 从大到小排列。
//声明一个Block变量,这个NSComparator是系统提供的一个比较Block,返回值是一个枚举值,NSOrderedSame = 0
完全一样,NSOrderedAscending = -1,NSOrderedDescending = +1
NSComparator sortBlock = ^(id string1, id string2)
{
return [string1 compare:string2];
};
//使用一个比较Block对数组进行排序,返回一个数组的元素以升序排序的数组
NSArray *sortArray = [stringArray sortedArrayUsingComparator:sortBlock];
NSLog(@"sortArray:%@", sortArray);
[array sortedArrayUsingComparator:^NSComparisonResult(id obj1, id obj2){
return [obj1 compare:obj2];
}];
7.描述static修饰符、const修饰符的区别。
const :主要的目的是防止修改对象的内容,定义的常量在函数执行之后其空间会被释放;
static主要的目的是作为类作用域的全局函数。不能访问类的非静态数据成员,定义的静态常量在函数执行后不会被释放其空间。
8.JSON和XML接口上的区别以及数据模式
- 可读性:JSON和XML的可读性可谓不相上下,一边是简易的语法,一边是规范的标签形式,很难分出胜负。
- 可扩展性:XML天生有很好的扩展性,JSON当然也有,没有什么是XML能扩展,JSON不能的。不过JSON在Javascript主场作战,可以存储Javascript复合对象,有着xml不可比拟的优势。
- 编码难度:XML有丰富的编码工具,比如Dom4j、JDom等,JSON也有提供的工具。
- 是否易于在服务器端创建数据:json相对于XML并不是望尘莫及,但还是略微逊色一筹;
- 是否易于在客户端处理数据:请求返回的json格式响应数据是一件轻而易举的事情,可以很轻松的用KVC方法赋值获得数据;处理XML响应数据,你得通过DOM树,这是非常繁琐且容易出错的工作;
- 安全性:两者差不多
数据模式:
JSON和XML的轻/重量级的区别在于:JSON只提供整体解析方案,而这种方法只在解析较少的数据时才能起到良好的效果;而XML提供了对大规模数据的逐步解析方案,这种方案很适合于对大量数据的处理。
在编码上,虽然XML和JSON都有各自的编码工具,但是JSON的编码要比XML简单,即使不借助工具,也可以写出JSON代码,但要写 出好的 XML代码就有点困难;与XML一样,JSON也是基于文本的,且它们都使用Unicode编码,且其与数据交换格式XML一样具有可读性。
主观上来看,JSON更为清晰且冗余更少些。JSON网站提供了对JSON语法的严格描述,只是描述较简短。从总体来看,XML比较适合于标记文档,而JSON却更适于进行数据交换处理。
9.NSNotification的实现原理。
观察者只要向消息中心注册, 即可接受其他对象发送来的消息,这种消息通知机制可以应用于任意时间和任何对象,观察者可以有多个,所以消息具有广播的性质.每个运行中的 application都有一个NSNotificationCenter的成员变量,它的功能就类似公共栏. 对象注册关注某个确定的notification(如果有人捡到一只小狗,就去告诉我). 我们把这些注册对象叫做 observer. 其它的一些对象会给center发送notifications(我捡到了一只小狗). center将该notifications转发给所有注册对该notification感兴趣的对象. 我们把这些发送notification的对象叫做 poster
NSNotificationCenter 较之于 Delegate 可以实现更大的跨度的通信机制,可以为两个无引用关系的两个对象进行通信。NSNotificationCenter 的通信原理使用了观察者模式:
1. NSNotificationCenter 注册观察者对某个事件(以字符串命名)感兴趣,及该事件触发时该执行的 Selector 或 Block
2. NSNotificationCenter 在某个时机激发事件(以字符串命名)
3. 观察者在收到感兴趣的事件时,执行相应的 Selector 或 Block
10.用obj-c 写一个冒泡排序。
NSMutableArray *p = [NSMutableArray arrayWithObjects:@"12",@"22",@"52",@"42",@"72",nil];
for (int i = 0; i< [p count] - 1; i++)
{
for (int j=0; j<[p count] - i - 1; j++)
{
int a = [[p objectAtIndex:i] intValue];
int b = [[p objectAtIndex:j] intValue];
if (a > b)
{
int temp = a;
[p replaceObjectAtIndex:i withObject:[NSString stringWithFormat:@"%d",b]];
[p replaceObjectAtIndex:j withObject:[NSString stringWithFormat:@"%d",temp]];
}
}
}
11.简述一下ARC.
ARC是iOS 5推出的新功能,全称叫 ARC(Automatic Reference Counting)。简单地说,就是代码中自动加入了retain/release,原先需要手动添加的用来处理内存管理的引用计数的代码可以自动地由编译器完成了。
使用ARC有什么好处呢?
- 看到上面的例子,大家就知道了,以后写Objective-C的代码变得简单多了,因为我们不需要担心烦人的内存管理,担心内存泄露了
- 代码的总量变少了,看上去清爽了不少,也节省了劳动力
- 代码高速化,由于使用编译器管理引用计数,减少了低效代码的可能性
12.网络的同步、异步连接有什么区别。
- 同步请求可以从因特网请求数据,一旦发送同步请求,程序将停止用户交互,直至服务器返回数据完成,才可以进行下一步操作,
- 异步请求不会阻塞主线程,而会建立一个新的线程来操作,用户发出异步请求后,依然可以对UI进行操作,程序可以继续运行
13.Core Animation这个框架的作用。
它是一套包含图形绘制,投影,动画的OC类集合。它就是一个framework。通过CoreAnimation提供的接口,你可以方便完成自己所想要的动画。
14.从程序包种读取文件,初始化一个数据data.
NSString *path = [[NSBundle mainBundle] pathForResource:nil ofType:nil];
NSData *data = [NSData dataWithContentsOfFile:path];
data = [NSData dataWithContentsOfFile:thepath];
扩展:
//第一种方法: NSFileManager实例方法读取数据
NSArray* paths = NSSearchPathForDirectoriesInDomains(NSDesktopDirectory, NSUserDomainMask, YES);
NSString* thepath = [paths lastObject];
thepath = [thepath stringByAppendingPathComponent:@
"fd_list.txt"
];
NSLog(@
"桌面目录:%@"
, thepath);
NSFileManager* fm = [NSFileManager defaultManager];
NSData* data = [[NSData alloc] init];
data = [fm contentsAtPath:thepath];
NSLog(@
"%@"
,[[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding]);
//第二种方法: NSData类方法读取数据
data = [NSData dataWithContentsOfFile:thepath];
NSLog(@
"NSData类方法读取的内容是:%@"
,[[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding]);
//第三种方法: NSString类方法读取内容
NSString* content = [NSString stringWithContentsOfFile:thepath encoding:NSUTF8StringEncoding error:nil];
NSLog(@
"NSString类方法读取的内容是:
%@"
,content);
//第四种方法: NSFileHandle实例方法读取内容
NSFileHandle* fh = [NSFileHandle fileHandleForReadingAtPath:thepath];
data = [fh readDataToEndOfFile];
NSLog(@
"NSFileHandle实例读取的内容是:
%@"
, [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding]);
15.简述属性的设置选项的作用,nonatomic,atomic,assign,retain,copy,read,readwrite,readonly
atomic:
原子操作(原子性是指事务的一个完整操作,操作成功就提交,反之就回滚. 原子操作就是指具有原子性的操作)在objective-c 属性设置里面 默认的就是atomic ,意思就是 setter /getter函数是一个原子操作,如果多线程同时调用setter时,不会出现某一个线程执行完setter所有语句之前,另一个线程就开始执行setter,相当于 函数头尾加了锁 . 这样的话 并发访问性能会比较低 .
nonatomic:
非原子操作 一般不需要多线程支持的时候就用它,这样在 并发访问的时候效率会比较高 . 在objective-c里面通常对象类型都应该声明为非原子性的. iOS中程序启动的时候系统只会自动生成一个单一的主线程.程序在执行的时候一般情况下是在同一个线程里面对一个属性进行操作. 如果在程序中 我们确定某一个属性会在多线程中被使用,并且需要做数据同步,就必须设置成原子性的,但也可以设置成非原子性的,然后自己在程序中用加锁之类的来做数据同步.
在头文件中声明属性的时候使用atomic 和 nonatomic等价于在头文件里面添加2个函数一个是用于设置这个属性的,一个是用于读取这个属性,例如:- (nsstring *)name; - (void)setName:(NSString *)str;
atomic / nonatomic 需要和@synthesize/@dynamic配和使用才有意义.
@synthesize
如果没有实现setter和getter方法,编译器将会自动在生产setter和getter方法。
@dynamic
表示变量对应的属性访问器方法 , 是动态实 现的 , 你需要在 NSObject 中继承而来的 +(BOOL) resolveInstanceMethod:(SEL) sel 方法中指定 动态实现的方法或者函数。
属性修饰其他关键字:
getter=getterName
指定 get 方法,并需要实现这个方法 。必须返回与声明类型相同的变量,没有参数
setter=setterName
指定 set 方法,并需要实现这个方法 。带一个与声明类型相同的参数,没有返回值(返回空值)
当声明为 readonly 的时候,不能指定 set 方法
readwrite
如果没有声明成 readonly ,那就 默认是 readwrite 。可以用来赋值,也可以被赋值
readonly
不可以被赋值
assign
所有属性都 默认 assign ,通常用于标量(简单变量 int , float , CGRect 等)
一种典型情况是用在对对象没有所有权的时候,通常是 delegate ,避免造成死循环(如果用 retain 的话会死循环)
retain
属性必须是 objc 对象,拥有对象所有权,必须在 dealloc 中 release 一次。
copy
属性必须是 objc 对象,拥有对象所有权,必须在 dealloc 中 release 一次。且属性必须实现 NSCopying 协议
一般常用于 NSString 类型
16.堆和栈的区别
管理方式:
对于栈来讲,是由编译器自动管理,无需我们手工控制;对于堆来讲,释放工作有程序员控制,容易产生memory Leak。
申请大小:栈: 在Windows下,栈是向低地址扩展的数据结构,是一块连续的内存区域。这句话的意思是栈顶上的地址和栈的最大容量是系统预先规定好的,在 Windows下,栈的大小是2M(也有的说1M,总之是编译器确定的一个常数),如果申请的空间超过了栈的剩余空间时候,就overflow。因此,能 获得栈的空间较小。
堆:堆是向高地址扩展的数据结构,是不连续的内存区域。这是由于系统是用链表来存储的空闲内存地址的,自然是不连续的,而链表的遍历方向是由低地址向高地址。堆的大笑受限于计算机系统中有效的虚拟内存。由此可见,堆获得的空间比较灵活,也比较大。
碎片的问题:对于堆来讲,频繁的new/delete势必会造成内存空间的不连续,从而造成大量的碎片,使程序效率降低。对于栈来讲,则不会存在这个问题,因为栈是先进后出的队列,他们是如此的一一对应,以至于永远都不可能有一个内存快从栈中弹出。
分配方式:堆都是动态分配的,没有静态分配的堆。栈有两种分配方式:静态分配和动态分配。静态分配是编译器完成的,比如局部变量的分配。动态分配是有alloc函数进行分配的,但是栈的动态分配和堆是不同的,他的动态分配由编译器进行释放,无需我们手工实现。
分配效率:栈是机器系统提供的数据结构,计算机会在底层堆栈提供支持,分配专门的寄存器存放栈的地址,压栈出栈都有专门的指令执行,这就决定了栈的效率比较高。堆则是C/C++函数库提供的,他的机制是很复杂的。
17.写一个便利构造器
//第一种方法,获取当前字符的位置
NSRange range = [str rangeOfString:@"|"];
NSString *beforStr = [str substringToIndex:range.location];
NSString *afterStr = [str substringFromIndex:range.location];
NSLog(@"%@,%@",beforStr,afterStr);
//第二种方法,通过分隔,返回一个数组
NSArray *array = [str componentsSeparatedByString:@"|"];
[array enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) {
NSLog(@"..%@..", obj);
}];
1. UIView是iOS系统中界面元素的基础,所有的界面元素都是继承自它。它本身完全是由CoreAnimation来实现的。它真正的绘图部分,是由一 个CALayer类来管理。UIView本身更像是一个CALayer的管理器,访问它的跟绘图和跟坐标有关的属性,例如frame,bounds等,实 际上内部都是在访问它所包含的CALayer的相关属性。
2. UIView有个重要属性layer,可以返回它的主CALayer实例。
// 要访问层,读取UIView实例的layer属性
CALayer *layer = myView.layer
所有从UIView继承来的对象都继承了这个属性。这意味着你可以转换、缩放、旋转,甚至可以在Navigation bars,Tables,Text boxes等其它的View类上增加动画。每个UIView都有一个层,控制着各自的内容最终被显示在屏幕上的方式。
UIView的layerClass方法,可以返回主layer所使用的类,UIView的子类可以通过重载这个方法,来让UIView使用不同的CALayer来显示。代码示例:
- (class)layerClass {
return ([CAEAGLLayer class]);
}
上述代码使得某个UIView的子类使用GL来进行绘制。
3. UIView的CALayer类似UIView的子View树形结构,也可以向它的layer上添加子layer,来完成某些特殊的表示。即CALayer层是可以嵌套的。示例代码:
grayCover = [[CALayer alloc] init];
grayCover.backgroundColor = [[UIColor blackColor] colorWithAlphaComponent:0.2] CGColor];
[self.layer addSubLayer:grayCover];
上述代码会在目标View上敷上一层黑色透明薄膜的效果。
4. UIView的layer树形在系统内部,被维护着三份copy。分别是逻辑树,这里是代码可以操纵的;动画树,是一个中间层,系统就在这一层上更改属性,进行各种渲染操作;显示树,其内容就是当前正被显示在屏幕上得内容。
5. 动画的运作:对UIView的subLayer(非主Layer)属性进行更改,系统将自动进行动画生成,动画持续时间的缺省值似乎是0.5秒。
6. 坐标系统:CALayer的坐标系统比UIView多了一个anchorPoint属性,使用CGPoint结构表示,值域是0~1,是个比例值。这个点是各种图形变换的坐标原点,同时会更改layer的position的位置,它的缺省值是{0.5,0.5},即在layer的中央。
某layer.anchorPoint = CGPointMake(0.f,0.f);
如果这么设置,只会将layer的左上角被挪到原来的中间位置,必须加上这一句:
某layer.position = CGPointMake(0.f,0.f);
最后:layer可以设置圆角显示(cornerRadius),也可以设置阴影 (shadowColor)。但是如果layer树中某个layer设置了圆角,树种所有layer的阴影效果都将不显示了。因此若是要有圆角又要阴影,变通方法只能做两个重叠的UIView,一个的layer显示圆角,一个layer显示阴影......
7.渲染:当更新层,改变不能立即显示在屏幕上。当所有的层都准备好时,可以调用setNeedsDisplay方法来重绘显示。
[gameLayer setNeedsDisplay];
若要重绘部分屏幕区域,请使用setNeedsDisplayInRect:方法,通过在CGRect结构的区域更新:
[gameLayer setNeedsDisplayInRect:CGRectMake(150.0,100.0,50.0,75.0)];
如果是用的Core Graphics框架来执行渲染的话,可以直接渲染Core Graphics的内容。用renderInContext:来做这个事。
[gameLayer renderInContext:UIGraphicsGetCurrentContext()];
8.变换:要在一个层中添加一个3D或仿射变换,可以分别设置层的transform或affineTransform属性。
characterView.layer.transform = CATransform3DMakeScale(-1.0,-1.0,1.0);
CGAffineTransform transform = CGAffineTransformMakeRotation(45.0);
backgroundView.layer.affineTransform = transform;
9.变形:Quartz Core的渲染能力,使二维图像可以被自由操纵,就好像是三维的。图像可以在一个三维坐标系中以任意角度被旋转,缩放和倾斜。CATransform3D的一套方法提供了一些魔术般的变换效果。
app收到Memory Warning后会调用:UIApplication::didReceiveMemoryWarning -> UIApplicationDelegate::applicationDidReceiveMemoryWarning,然后调用当前所有的viewController进行处理。因此处理的主要工作是在viewController。
注:面试题为收集他人资源。