面试题的总结(一)
一.MRC 和ARC 内存管理?
Objective-c中提供了两种内存管理机制MRC(MannulReference Counting)和ARC(Automatic Reference Counting),分别提供对内存的手动和自动管理,来满足不同的需求。其实arc 内部机制原理也是来源于mrc ,arc 是在 iOS 5/ Mac OS X 10.7 开始导入,利用 Xcode4.2 可以使用该机能。arc的首要目的就是让代码简洁化,编程简单化,开发更顺心应手,减少不必要的小问题小疏忽;顾名思义,自动引用计数管理,关于内存的申请,使用和释放过程都交给系统自动实现,我们可也不用关系里面的过程,但是事实上还是mrc的原理,只是是系统帮我们做了管理;
mrc,手动引用计数器管理,是在我们申请到某一块内存,在使用之后,要手动释放,释放机理涉及到计数器问题,如果未释放内存,会造成内存的浪费,俗称内存泄露,甚至引起很多未知的错误结果,这对程序有威胁很大,但是,何时释放,怎么释放,注意哪些问题,很有讲究,这就是mrc的不便之处,也是苹果推出arc的缘由;
mrc的具体机理,计数器是什么,在程序过程中的变化,在达到什么程度会释放内存,怎么操作;建议查阅相关文档;
mrc ,在代码上下形式主要表现为,调用该对象时,要做retain操作,使用完成后要release,最后还要重写dealloc方法,对该类的所有对象做释放,所以在mrc的代码会有autorelease,retain,release等词语,
而arc不允许有这些词汇,应为这些操作都由系统自动完成。
引用计数器
1.和内存管理相关的方法
1)alloc 引用计数器自动设为1
2)retain 引用计数器+1 返回了经过+1以后的当前实例对象
3)release 引用计数器-1,并不一定是释放
4)retainCount 获取引用计数器的值
5)dealloc 当实例对象被销毁之前,系统自动调用。
一定要调[super dealloc]
和内存管理相关的名词
1)僵尸对象:此对象被销毁,不能再使用,不能给它发送任何消息
2)野指针:指向僵尸对象(不可用的内存)的指针,给野指针发送消息将会产生不可控的后果。
3)空指针:没有指向任何对象的指针,给空指针发消息不会产生任何行为
内存管理原则
1.如果你想持有某个对象,就必须负责让做一次retain操作,引用计数器+1.
2.如果你想放弃对某个对象的持有权,就要负责让其做一次release操作,引用计数器-1.
3.谁retain,谁release。
二.retain 和copy的区别?
copy是创建一个新对象,retain是创建一个指针,引用对象计数加1。Copy属性表示两个对象内容相同,新的对象retain为1 ,与旧有对象的引用计数无关,旧有对象没有变化。copy减少对象对上下文的依赖。
retain属性表示两个对象地址相同(建立一个指针,指针拷贝),内容当然相同,这个对象的retain值+1也就是说,retain 是指针拷贝,copy 是内容拷贝。
三、CALayer 的用处?
1.UIView是iOS系统中界面元素的基础,所有的界面元素都继承自它。它本身完全是由CoreAnimation来实现的(Mac下似乎不是这样)。它真正的绘图部分,是由一个叫CALayer(Core Animation Layer)的类来管理。UIView本身,更像是一个CALayer的管理器,访问它的跟绘图和跟坐标有关的属性,例如frame,bounds等等,实际上内部都是在访问它所包含的CALayer的相关属性。 2.UIView有个layer属性,可以返回它的主CALayer实例,UIView有一个layerClass方法,返回主layer所使用的类,UIView的子类,可以通过重载这个方法,来让UIView使用不同的CALayer来显示,例如通过 1 - (class) layerClass { 2 return ([CAEAGLLayer class]); 3 } 使某个UIView的子类使用GL来进行绘制。 3.UIView的CALayer类似UIView的子View树形结构,也可以向它的layer上添加子layer,来完成某些特殊的表示。例如下面的代码 1 grayCover = [[CALayer alloc] init]; 2 grayCover.backgroundColor = [[[UIColor blackColor] colorWithAlphaComponent:0.2] CGColor]; 3 [self.layer addSubLayer: grayCover]; 会在目标View上敷上一层黑色的透明薄膜。 4.UIView的layer树形在系统内部,被系统维护着三份copy(这段理解有点吃不准)。 第一份,逻辑树,就是代码里可以操纵的,例如更改layer的属性等等就在这一份。 第二份,动画树,这是一个中间层,系统正在这一层上更改属性,进行各种渲染操作。 第三份,显示树,这棵树的内容是当前正被显示在屏幕上的内容。 这三棵树的逻辑结构都是一样的,区别只有各自的属性。 5.动画的运作 UIView的主layer以外(我觉得是这样),对它的subLayer,也就是子layer的属性进行更改,系统将自动进行动画生成,动画持续时间有个缺省时间,个人感觉大概是0.5秒。在动画时间里,系统自动判定哪些属性更改了,自动对更改的属性进行动画插值,生成中间帧然后连续显示产生动画效果。 6.坐标系系统(对position和anchorPoint的关系还是犯晕) 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);
四、多线程?
进程:
正在进行中的程序被称为进程,负责程序运行的内存分配;
每一个进程都有自己独立的虚拟内存空间.
线程:(主线程最大占1M的栈区空间,每条子线程最大占512K的栈区空间)
线程是进程中一个独立的执行路径(控制单元);
一个进程中至少包含一条线程,即主线程;
可以将耗时的执行路径(如网络请求)放在其他线程中执行;
线程不能被杀掉,但是可以暂停/休眠一条线程.
创建线程的目的:
开启一条新的执行路径,运行指定的代码,与主线程中的代码实现同时运行.
多任务调度系统:
每个应用程序由操作系统分配的短暂的时间片(Timeslice)轮流使用CPU,由于CPU对每个时间片的处理速度非常快,因此,用户看来这些任务好像是同时执行的.
并发:
指两个或多个任务在同一时间间隔内发生,但是,在任意一个时间点上,CPU只会处理一个任务.
多线程的优势:
1> 充分发挥多核处理器优势,将不同线程任务分配给不同的处理器,真正进入"并行运算"状态;
2> 将耗时的任务分配到其他线程执行,由主线程负责统一更新界面会使应用程序更加流畅,用户体验更好;
3> 当硬件处理器的数量增加,程序会运行更快,而程序无需做任何调整.
弊端:
新建线程会消耗内存空间和CPU时间,线程太多会降低系统的运行性能.
五、iOS多线程技术特点?
1.NSThread:
1> 使用NSThread对象建立一个线程非常方便;
2> 但是!要使用NSThread管理多个线程非常困难,不推荐使用;
3> 技巧!使用[NSThread currentThread]跟踪任务所在线程,适用于这三种技术.
2.NSOperation/NSOperationQueue:
1> 是使用GCD实现的一套Objective-C的API;
2> 是面向对象的多线程技术;
3> 提供了一些在GCD中不容易实现的特性,如:限制最大并发数量,操作之间的依赖关系.
3.GCD---Grand Central Dispatch:
1> 是基于C语言的底层API;
2> 用Block定义任务,使用起来非常灵活便捷;
3> 提供了更多的控制能力以及操作队列中所不能使用的底层函数.
iOS的开发者需要了解三种多线程技术的基本使用,因为在实际开发中会根据实际情况选择不同的多线程技术.
GCD基本思想
GCD的基本思想就是将操作S放在队列S中去执行.
1> 操作使用Blocks定义;
2> 队列负责调度任务执行所在的线程以及具体的执行时间;
3> 队列的特点是先进先出(FIFO)的,新添加至队列的操作都会排在队尾.
提示:
GCD的函数都是以dispatch(分派/调度)开头的.
队列:
dispatch_queue_t
串行队列: 队列中的任务只会顺序执行;
并行队列: 队列中的任务通常会并发执行.
操作:
dispatch_async 异步操作,会并发执行,无法确定任务的执行顺序;
dispatch_sync 同步操作,会依次顺序执行,能够决定任务的执行顺序.
队列不是线程,也不表示对应的CPU.队列就是负责调度的.多线程技术的目的,就是为了在一个CPU上实现快速切换!
在串行队列中:
同步操作不会新建线程,操作顺序执行(没用!);
异步操作会新建线程,操作顺序执行(非常有用!) (应用场景:既不影响主线程,又需要顺序执行的操作).
在并行队列中:
同步操作不会新建线程,操作顺序执行;
异步操作会新建多个线程,操作无序执行(有用,容易出错),队列前如果有其他任务,会等待前面的任务完成之后再执行.应用场景:既不影响主线程,又不需要顺序执行的操作.
全局队列:
全局队列是系统的,直接拿过来(GET)用就可以,与并行对立类似,但调试时,无法确认操作所在队列.
主队列:
每一个应用程序都对应唯一一个主队列,直接GET即可,在多线程开发中,使用主队列更新UI;
注意:
主队列中的操作都应该在主线程上顺序执行,不存在异步的概念.
如果把主线程中的操作看作是一个大的Block,那么除非主线程被用户杀掉,否则永远不会结束.所以主队列中添加的同步操作永远不会被执行,会死锁.
// 全局队列,都在主线程上执行,不会死锁
dispatch_queue_t q = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
// 并行队列,都在主线程上执行,不会死锁
dispatch_queue_t q = dispatch_queue_create("m.baidu.com", DISPATCH_QUEUE_CONCURRENT);
// 串行队列,会死锁,但是会执行嵌套同步操作之前的代码
dispatch_queue_t q = dispatch_queue_create("m.baidu.com", DISPATCH_QUEUE_SERIAL);
// 直接死锁
dispatch_queue_t q = dispatch_get_main_queue();
同步操作dispatch_sync的应用场景:
阻塞并行队列的执行,要求某一操作执行后再进行后续操作,如用户登录.
确保块代码之外的局部变量确实被修改.
[NSThread sleepForTimeInterval:2.0f] 通常在多线程调试中用于模拟耗时操作,在发布的应用程序中,不要使用此方法!
无论什么队列和什么任务,线程的创建和回收都不需要程序员参与.线程的创建回收工作是由队列负责的.
GCD优点:
1> 通过GCD,开发者不用再直接跟线程打交道,只需要向队列中添加代码块即可.
2> GCD在后端管理着一个线程池,GCD不仅决定着代码块将在哪个线程被执行,它还根据可用的系统资源对这些线程进行管理,从而让开发者从线程管理的工作中解放出来;通过集中的管理线程,缓解大量线程被创建的问题.
3> 使用GCD,开发者可以将工作考虑为一个队列,而不是一堆线程,这种并行的抽象模型更容易掌握和使用.
六、CoreAnimation?
CAAnimation可分为四种:
1.CABasicAnimation
通过设定起始点,终点,时间,动画会沿着你这设定点进行移动。可以看做特殊的CAKeyFrameAnimation
2.CAKeyframeAnimation
Keyframe顾名思义就是关键点的frame,你可以通过设定CALayer的始点、中间关键点、终点的frame,时间,动画会沿你设定的轨迹进行移动
3.CAAnimationGroup
Group也就是组合的意思,就是把对这个Layer的所有动画都组合起来。PS:一个layer设定了很多动画,他们都会同时执行,如何按顺序执行我到时候再讲。
4.CATransition
这个就是苹果帮开发者封装好的一些动画
补充:
•Core Animation是非常强大的动画处理API,使用它能做出非常炫丽的动画效果,而且往往是事半功倍,使用它需要先添加QuartzCore.framework和引入对应的框架<QuartzCore/QuartzCore.h>
•CALayer中很多属性都可以通过CAAnimation实现动画效果,包括:opacity、position、transform、bounds、contents等(可以在API文档中搜索:CALayer Animatable Properties)
•通过调用CALayer的addAnimation:forKey增加动画到层(CALayer)中,这样就能触发动画了。通过调用removeAnimationForKey可以停止层中的动画
•Core Animation的动画执行过程都是在后台操作的,不会阻塞主线程
开发步骤
①初始化一个动画对象(CAAnimation)并设置一些动画相关属性
②添加动画对象到层(CALayer)中,开始执行动画
①CAAnimation
七、sdwebimage
实现加载网络图片,并可以设置图片加载前的默认图片,监听图片加载进度以及图片加载完成事件
#import导入"UIImageView+WebCache.h",
[_imageView setImageWithURL:url placeholderImage:nil options:SDWebImageRetryFailed progress:^(NSInteger receivedSize, NSInteger expectedSize) {//查看下载进度
NSLog(@"receive = %d,expected = %d",receivedSize,expectedSize);
} completed:^(UIImage *image, NSError *error, SDImageCacheType cacheType) {//加载成功后调用
NSLog(@"加载成功");
}];
调用此方法会下载URL所指向的网络图片(如果本地无缓存的话),并且可以监听下载进度以及下载完成事件
#import导入“SDImageCache.h”可实现储存加载的图像到缓存,并且可以找出储存的缓存,使图片显示
八、SizeClass 本质上就是AutoLayout
AutoLayout到底是什么?其实就是个约束布局
如果你用了AutoLayout 那么做动画的时候 你就不要再操作 Frame bounds center 等position属性
因为这些动画都是临时的 下次的View 被 setNeedsUpdateConstraint 这些全都失效
但是其他的可动画属性(Animation Properties) 还是可以的 如 Color alpha等
NSLayoutConstraint
UIButton *button=[[UIButton alloc]init];
[button setTitle:@"点击一下" forState:UIControlStateNormal];
button.translatesAutoresizingMaskIntoConstraints=NO;
[button setBackgroundColor:[UIColor blackColor]];
[self.view addSubview:button];
NSArray *constraints1=[NSLayoutConstraint constraintsWithVisualFormat:@"H:|-[button]-|"
options:0
metrics:nil
views:NSDictionaryOfVariableBindings(button)];
NSArray *constraints2=[NSLayoutConstraint constraintsWithVisualFormat:@"V:|-20-[button(==30)]"
options:0
metrics:nil
views:NSDictionaryOfVariableBindings(button)];
[self.view addConstraints:constraints1];
[self.view addConstraints:constraints2];
九、delegate和Notification的区别?
delegate针对one-to-one关系,并且reciever可以返回值给sender;
notification 可以针对one-to-one/many/none,reciever无法返回值给sender;
所以,delegate用于sender希望接受到reciever的某个功能反馈值,notification用于通知多个object某个事件。
delegate主动,notification被动
1.
Delegate:
消息的发送者(sender)告知接收者(receiver)某个事件将要发生,delegate同意然后发送者响应事件,delegate机制使得接收者可以改变发送者的行为。通常发送者和接收者的关系是直接的一对多的关系。
Notification:
消息的发送者告知接收者事件已经发生或者将要发送,仅此而已,接收者并不能反过来影响发送者的行为。通常发送者和接收者的关系是间接的多对多关系。
2.
简单说,
1. 效率肯定是delegate比nsnotification高。
2. delegate方法比notification更加直接,最典型的特征是,delegate方法往往需要关注返回值,也就是delegate方法的结果。
notification
在IOS应用开发中有一个”Notification Center“的概念。它是一个单例对象,允许当事件发生时通知一些对象。它允许我们在低程度耦合的情况下,满足控制器与一个任意的对象进行通信的目的。这种模式的基本特征是为了让其他的对象能够接收到在该controller中发生某种事件而产生的消息,controller用一个key(通知名称)。这样对于controller来说是匿名的,Source Code其他的使用同样的key来注册了该通知的对象(即观察者)能够对通知的事件作出反应。
优势:
1.不需要编写多少代码,实现比较简单;
2.对于一个发出的通知,多个对象能够做出反应,即1对多的方式实现简单
3.controller能够传递context对象(dictionary),context对象携带了关于发送通知的自定义的信息
缺点:
1.在编译期不会检查通知是否能够被观察者正确的处理;
2.在释放注册的对象时,需要在通知中心取消注册;
3.在调试的时候应用的工作以及控制过程难跟踪;
4.需要第三方对喜爱那个来管理controller与观察者对象之间的联系;
5.controller和观察者需要提前知道通知名称http://www.androide-apps.com/、UserInfo dictionary keys。如果这些没有在工作区间定义,那么会出现不同步的情况;
6.通知发出后,controller不能从观察者获得任何的反馈信息。