iOS 知识小册子 第一期

由于每天接触的东西很多,有些知识不记录下来忘记的也快,等于做了无用功,受南峰子技术博客的启发,准备把平常接触到的iOS相关的知识点记录下来,方便以后学习,温故

本期主要记录以下问题:

1. delegate 为啥要用 weak 修饰?

2. 什么情况使用 weak 关键字,相比 assign 有什么不同?

3. 怎么用 copy 关键字?

4. 这个写法会出什么问题:@property (copy) NSMutableArray *array

5. 如何让自己的类用 copy 修饰符?如何重写带 copy 关键字的 setter?

6. @synthesize 和 @dynamic 分别有什么作用?

7. ARC下,不显式指定任何属性关键字时,默认的关键字都有哪些?

8. 什么时候会报 unrecognized selector 的异常?

9.  一个 OC 对象的 isa 的指针指向什么?有什么作用?

10. runtime 如何通过 selector 找到对应的 IMP 地址?

11. 使用 runtime Associate方法关联的对象,需要在主对象dealloc的时候释放么?

12. runloop 和线程有什么关系?

13. runloop 的 mode 作用是什么?

14. 猜想 runloop 内部是如何实现的?

15. 使用 block 时什么情况会发生引用循环,如何解决?

16. GCD的队列(dispatch_queue_t)分哪两种类型?

17. 如何用GCD同步若干个异步调用?(如根据若干个url异步加载多张图片,然后在都下载完成后合成一张整图)

18 .dispatch_barrier_async的作用是什么?

19. 苹果为什么要废弃dispatch_get_current_queue?

20. addObserver:forKeyPath:options:context:各个参数的作用分别是什么,observer中需要实现哪个方法才能获得KVO回调?

21. 如何手动触发一个value的KVO?


delegate 为啥要用 weak 修饰?

用 weak 表明该对象的销毁由外部控制, 由于 delegate 的不确定性和非拥有性, 在 ARC 中应该首选 weak,  因为 weak 可以防止野指针和循环引用的问题, 更加安全, 当 delegate 被销毁的时候, deleagte 会被清空 (nill)

如果在iOS5.0下, 未支持 weak, 只能使用 unsafe_unretained 代替

代码参考http://www.jianshu.com/p/398472616435

补充: A 对象想要监听 B 对象的事件可以设置 B 的 deleagte 为 A

什么情况使用 weak 关键字,相比 assign 有什么不同?

1. 在 ARC 有可能出现循环引用的情况, 比如 delegate

2. 自身已经对他进行了一次 strong 引用或者有父控件对他强引用, 比如 IBOutlet 控件属性

和 assign 不同之处:

1. 和 assign 一样在 setter 方法中既不会 release 旧值, 也不会 retain 新值, 但是 weak 修饰的对象销毁时, 会清空该属性对象避免野指针

2. assign 可以用在非 OC 对象, weak 只能用在 OC 对象 

怎么用 copy 关键字?

1. NSString, NSArray, NSDictionary 等经常使用 copy, 因为他们有对应的可变类型(避免多态造成运行时程序崩溃)

2. block 经常使用 copy, 这个是MRC遗留下来的传统, 在MRC 中 block 是分配到栈中的,内存由系统管理, 使用 copy 可以把 block 拷贝一份到堆区, 由程序员管理, 在 ARC 中编译器会对自动对 block 进行 copy 操作 

copy 也涉及浅拷贝和深拷贝的问题, 如果是对可变的变量进行 copy 操作是深拷贝, 会在内存中创建新的对象, 源对象的改变不会影响新的对象, 新的对象 retainCount 加 1, 源对象 retainCount 不变; 如果是对不可变的变量进行 copy 操作不会产生新的对象, 源对象引用计数加 1, 相当于 retain

NSMutableCopy 都是深拷贝操作

使用 copy 主要是向在内存中拷贝一个新的对象, 并且源对象改变以后不会影响新的对象

这个写法会出什么问题:@property (copy) NSMutableArray *array

1. NSMutableArray 如果属性是 copy 的话在.m生成的setter方法中会拷贝一个新的不可变的数组赋值给 NSMutableArray 的变量名, 实质是 NSArray, 由于NSArray是比不可变的, 用NSMutableArray的方法来动态修改新的对象在运行时会报错

-[__NSArrayI addObject:]: unrecognized selector sent to instance 0x7ff240614b40

2. @property 应该加上 nonatomic, 默认是 atomic 多线程安全, 在生成的getter 和 setter器中会加同步锁, 但是会影响性能 

如何让自己的类用 copy 修饰符?如何重写带 copy 关键字的 setter?

1. 声明该类遵从 NSCopy 协议 (NSCoding 协议用在归档中)

2. 实现NSCopying协议的 copyWithZone 方法

- (id)copyWithZone:(NSZone *)zone {

   Student *student = [[[self Class] allocWithZone:zone] init];

  student.name = self.name;

  return student;

}


重写带 copy 关键字的 setter 器 

- (void)setName:(NSString *)name {

    if(_name != name) {

         [_name release];

         [_name copy];

    }

}

@synthesize 和 @dynamic 分别有什么作用?

如果 @synthesize和@dynamic都没写,那么默认的就是@syntheszie var = _var; 

另外@synthesize 和 @dynamic 是互斥的, 不能同时存在

@synthesize 如果没有重写 getter 和 setter 方法, 编译器会加上这两个方法和待下划线的成员变量

@dynamic告诉编译器属性的 getter 和 setter 方法, 用户自己实现, 不自动生成, 如果某个属性声明了 @dynamic 又没有自己实现 getter 和 setter 方法, 编译的时候 OK, 但是程序如果调用 getter 和 setter 方法就会导致程序崩溃, 编译OK, 运行才执行相应的方法就是动态绑定

ARC下,不显式指定任何属性关键字时,默认的关键字都有哪些?

OC对象: strong, atomic, readwrite

基本数据类型: assign, atomic, readwrite

什么时候会报 unrecognized selector 的异常?

OC 在向一个对象发送消息时, runtime 库会根据对象的 isa 指针找到该对象实际所属的类, 然后在该类及该类的父类方法列表寻找方法运行, 但是如果在最顶层的类中依然无法找到该方法, 程序运行时会抛此异常. 在程序崩溃之前 runtime 会给出第三次拯救程序的机会:

1. Method resolution(动态消息解析)

OC 运行时会调用 + resolveInstanceMethod: 或者 + resolveClassMethod: 让你有机会添加一个函数. 如果添加了函数并返回 YES,  runtime会重新启动一次消息发送的过程, 如果resolve 方法返回NO, 运行时会移到下一步, 消息转发(message forward)

PS: 可以利用消息转发实现多继承下面再说

2. Fast Forwarding

如果目标对象实现了- forwardingTargetForSelector: runtime 这时就会调用该方法, 给你把这个消息转发给其他对象的机会, 只要这个方法返回的不是 nil (返回 self 会造成死循环) 整个消息发送的过程就会被重启, 当然发送的对象会变成你返回的那个对象, 否则会进行 Normal Forwarding

这里不创建任何新的对象, 所以相对 Normal Forwarding(会创建 NSInvocation 对象)速度快

3. Normal Forwarding

这是 runtime 最后一次给你机会拯救程序的机会, 首先会发送 - methodSignatureForSelector: 获得函数的参数和返回值类型, 如果该方法返回 nil, 程序这个时候就崩溃了(发送 - doesNotRecognizeSelector: 消息), 如果返回函数签名, Runtime 就会创建一个 NSInvocation 对象, 并发送 - forwardInvocation: 消息给目标对象

一个 OC 对象的 isa 的指针指向什么?有什么作用?

指向他(对象)的类对象, 从而可以找到对象上的方法

"Objective-C 是一门面向对象的编程语言。每一个对象都是一个类的实例。在 Objective-C 语言的内部,每一个对象都有一个名为 isa 的指针,指向该对象的类。每一个类描述了一系列它的实例的特点,包括成员变量的列表,成员函数的列表等。每一个对象都可以接受消息,而对象能够接收的消息列表是保存在它所对应的类中。" 

-- 来自唐巧博客http://blog.devtang.com/blog/2013/10/15/objective-c-object-model/

runtime 如何通过 selector 找到对应的 IMP 地址?

每一个类对象都有一个方法列表, 方法列表记录着方法的名称, 方法实现, 及方法的参数类型, selector的本质就是方法名, 通过这个方法名可以在对应的方法列表找到对应的方法实现

使用 runtime Associate 方法关联的对象,需要在主对象 dealloc的时候释放么?

ARC 不需要

MRC 在 retain 和 copy 策略下需要

runloop 和线程有什么关系?

runloop是为线程而生的, 每一个线程都会有一个对应的 runloop, 只不过主线程的 runloop 是默认开启的(这就解释了为什么应用会在无人操作的时候休息, 有人操作的时候工作), 可以通过 CFRunLoopRun 函数来开启一个消息循环 (如果线程去执行一个长的已经确定的任务则不需要开启消息循环)

SDWebImage有开起过子线程的消息循环

可以通过[NSRunLoop currentRunLoop]获得当前线程的 RunLoop

每次消息循环开始时创建自动释放池, 消息循环结束时释放消息自动释放池

runloop 的mode 作用是什么?

mode主要指定事件在循环中的优先级的, 苹果公开的有两个

NSDefaultRunLoopMode: 当把 NSTimer 以此模式添加到运行循环, 当用户有事件处理的时候, NSTimer 不再被调度

 NSRunLoopCommonModes: 以此模式添加运行循环, 当用户有事件处理, NSTimer 还能正常调度, 互不影响

猜想runloop内部是如何实现的?

runloop 是一个死循环, 从事件队列取出事件, 执行相关代码; 如过没有事件, 则挂起, 等有事件了立即唤醒消息循环, 开始执行

使用block时什么情况会发生引用循环,如何解决?

一个对象强引用了 block, 在 block 中又使用了该对象就会造成循环引用, 解决办法是将该对象使用__weak或者__block修饰符修饰之后再在block中使用。

__weak typeof(self) weakSelf =self;

GCD的队列(dispatch_queue_t)分哪两种类型?

1. 串行队列 Serial Dispatch Queue

2. 并发队列 Concurrent Dispatch Queue

如何用GCD同步若干个异步调用?(如根据若干个url异步加载多张图片,然后在都下载完成后合成一张整图)

1. 创建异步队列

dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT,0);

2. 创建dispatch_group

dispatch_group_t group = dispatch_group_create();

3. 通过组来执行异步下载任务

dispatch_group_async(group, queue, ^{/*加载图片1 */});

dispatch_group_async(group, queue, ^{/*加载图片2 */});

dispatch_group_async(group, queue, ^{/*加载图片3 */});

4. 任务完成之后合并图片(等组里面所有的任务都执行完了会调下面这个方法)

dispatch_group_notify(group, dispatch_get_main_queue(), ^{// 合并图片});

dispatch_barrier_async的作用是什么?

是在并行队列中, 等待前面操作并行任务执行完成后再执行dispatch_barrier_async中得任务, 如果后面还有并行任务会开始执行后续的并行任务

苹果为什么要废弃dispatch_get_current_queue?

容易造成死锁

addObserver:forKeyPath:options:context:各个参数的作用分别是什么,observer中需要实现哪个方法才能获得KVO回调?

观察者, 观察的属性, 观察的选项, 上下文

- (void)observeValueForKeyPath:(NSString*)keyPath ofObject:(id)object change:(NSDictionary*)change context:(void*)context;

如何手动触发一个 value 的 KVO

[self willChangeValueForKey:@"now"];“手动触发self.now的KVO”

[self didChangeValueForKey:@"now"];“手动触发self.now的KVO”

observeValueForKey:ofObject:change:context:

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 194,457评论 5 459
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 81,837评论 2 371
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 141,696评论 0 319
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,183评论 1 263
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 61,057评论 4 355
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,105评论 1 272
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,520评论 3 381
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,211评论 0 253
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,482评论 1 290
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,574评论 2 309
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,353评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,213评论 3 312
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,576评论 3 298
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 28,897评论 0 17
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,174评论 1 250
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,489评论 2 341
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,683评论 2 335

推荐阅读更多精彩内容