1.Runloop
简介: RunLoop就是让线程随时处理事件但不退出的机制 每一个线程都有一个RunLoop RunLoop 实际上就是一个对象,这个对象管理了其需要处理的事件(比如button的点击、各种手势的的事件、定时器、tableView的代理方法)和消息,是iOS里的一种事件处理机制。 线程执行了这个函数后,就会一直处于这个函数内部 “接受消息->等待->处理” 的循环中,直到这个循环结束(比如传入 quit 的消息),函数返回。
作用:
- 保持程序的持续运行(比如主运行循环)
- 处理App中的各种事件(比如触摸事件、定时器事件、Selector事件)
- 节省CPU资源,提高程序性能:该做事时做事,该休息时休息
2.Runtime:
它是 Objective-C 面向对象和动态机制的基石。 runtime是OC动态语言的运行时机制,OC的方法调用最后都转成了runtime的objc_msgSend函数。
- 消息发送
- 动态方法解析
- 消息转发
消息发送:
- 在Class的Cache缓存中,寻找对应的IMP(方法实现)
- 如果Cache中没有,就继续在Class的methodlist(方法列表)中找对应的selector
- 如果在class中,没有找到这个selector,就继续在它的superClass中的cache(方法缓存)中查找,
- 如果没有查到,就在superClass中的methodlist中查找,并且缓存到Class中的cache(方法缓存)中 5.如果还是没有找到IMP(方法实现),判断是否还是有superClass,如果有重复 4,5步骤,如果没有则开始进入到动态方法解析阶段
runtime实际应用:
- 给NSTimer定时器声明一个中间类Proxy(消息转发)
- 通过rumtime动态获取类的所有属性(json转model、可归档类对属性的归档及解归档操作)
- 反射机制(NSClassFromString, CTMediator原理)
- 交换系统方法(比如交换viewController生命周期方法,从而进行统一埋点等操作)
- 给分类添加属性(通过关联对象,实现getter, setter方法)
3.KVO
键值观察:对目标对象的某属性添加观察,当该属性发生变化时,通过触发观察者对象实现的KVO接口方法,来自动的通知观察者。
4.autorelasepool
在 ARC 下,我们不需要手动管理内存,可以完全不知道 autorelease 的存在,就可以正确管理好内存,因为 Runloop 在每个 Runloop Circle 中会自动创建和释放Autorelease Pool。 当我们需要创建和销毁大量的对象时,使用手动创建的 autoreleasepool 可以有效的避免内存峰值的出现。因为如果不手动创建的话,外层系统创建的 pool 会在整个 Runloop Circle 结束之后才进行 drain,手动创建的话,会在 block 结束之后就进行 drain 操作,比如下面例子:
比如SDWebImage中这段代码,由于encodedDataWithImage会把image解码成data,可能造成内存暴涨,所以加autoreleasepool避免内存暴涨
@autoreleasepool { NSData *data = imageData; if (!data && image) { // If we do not have any data to detect image format, check whether it contains alpha channel to use PNG or JPEG format SDImageFormat format; if ([SDImageCoderHelper CGImageContainsAlpha:image.CGImage]) { format = SDImageFormatPNG; } else { format = SDImageFormatJPEG; } data = [[SDImageCodersManager sharedManager] encodedDataWithImage:image format:format options:nil]; } [self _storeImageDataToDisk:data forKey:key]; }
5.CoreAnimation核心动画:
CAShapeLayer,根据路径矢量绘图 CATextLayer,文字图层(CATextLayer也要比UILabel渲染得快得多。很少有人知道在iOS 6及之前的版本,UILabel其实是通过WebKit来实现绘制的,这样就造成了当有很多文字的时候就会有极大的性能压力。而CATextLayer使用了Core text,并且渲染得非常快。) CATransformLayer,绘制3D图层 CAGradientLayer,渐变图层 CAReplicatorLayer,对称图层 CATiledLayer,超大大图分片显示
6.CoreText:
CoreText是iOS和Mac OS中文本处理的根基, TextKit和WebKit都是构建于其上。 基准线,上缘线,下缘线,上部,下部 CTFrame,CTLine,CTRun
7.你在开发过程中常用到哪些定时器,定时器时间会有误差吗,如果有,为什么会有误差?
iOS中常NSTimer、CADisplayLink、GCD定时器,其中NSTimer、CADisplayLink基于NSRunLoop实现,故存在误差,GCD定时器只依赖系统内核,相对一前两者是比较准时的。 误差原因是:与NSRunLoop机制有关, 因为RunLoop每跑完一次圈再去检查当前累计时间是否已经达到定时设置的间隔时间,如果未达到,RunLoop将进入下一轮任务,待任务结束之后再去检查当前累计时间,而此时的累计时间可能已经超过了定时器的间隔时间,故会存在误差。
8.NSString 为什么用 copy 修饰?用 strong 会有问题么?
因为如果用 strong 修饰,在进行 setter 时,传进来的是一个NSMutableString 也是可以赋值的(这里也有多态的体现),但是如果 NSMutableString 发生变化的话,由于是 strong 修饰, NSString 的那个对象也会发生变化且无感知,这种风险就存在了,
- 原子性。原子性有nonatomic、atomic两个值,如果不写nonatomic,那么默认是atomic的。如果属性是atomic的,那么在访问其getter和setter方法之前,会有一些判断,大概是判断是否可以访问等,这里系统使用的是自旋锁。由于使用atomic并不能绝对保证线程安全,且会耗费一些性能,因此通常情况下都使用nonatomic。
- 读写权限。读写权限有两个取值,readwrite和readonly。声明属性时,如果不指定读写权限,那么默认是readwrite的。如果某个属性不想让其他人来写,那么可以设置成readonly。
- 内存管理。内存管理的取值有assign、strong、weak、copy、unsafe_unretained。
- set、get方法名。如果不想使用自动合成所生成的setter、getter方法,声明属性时甚至可以指定方法名。比如指定getter方法