第一章 ARC
使用ARC的条件:
引用计数的机制
用开关房间的灯来作比喻,需要照明的人数(即引用数),当引用数大于0开灯,当引用数等于0关灯
1.2.2 内存管理的思考方式
按照此思考方式,完全不用考虑引用计数
- 自己生成的对象,自己持有
- 非自己生成的对象,自己也能持有
非自己生成的对象,即用alloc/new/copy/mutableCopy以外取得的对象
方法中生成对象,并将其返回给调用方是怎么实现的?
-
不再需要自己持有对象时释放
释放了非自己持有的对象就会造成崩溃
生成、持有、释放、废弃
这些内存管理的有关方法,实际上不包括在语言中,而是包含在Cocoa框架中。Cocoa框架中的Foundation框架类库的NSObject类担负内存管理的职责。
1.2.3 GNUstep alloc/retain/release/dealloc 的实现
参考资料
alloc
alloc -- allocWithZone -- NSAllocateObject -- NSZoneMalloc
NSZone:为了防止内存碎片化而引入的结构
retain
只是是retained变量+1
release
当retained变量大于0时候-1,当等于0的时候调用dealloc实例方法
1.2.4 苹果alloc/retain/release/dealloc 的实现
+alloc
+allocWithZone
class_createInstance
calloc
__CFDoExternRefOperation函数
苹果就是采用散列表(引用计数表)来管理引用计数。
- 对比GNUstep和苹果两种管理引用计数的方式
1.2.5 autorelease
1.2.6 GNUstep的autorelease实现
IMP 缓存
在GNUstep中,实际NSAutoreleasePool的addObject使用的是链表
1.2.7 苹果的autorelease实现
1.3 ARC规则
1.3.1
同一个程序中可以以文件为单位设置ARC有效/无效
1.3.3 所有权修饰符
第二章 Blocks
第三章 GCD
3.1 什么是GCD
使用GCD一般就两个步骤:
获取队列
调用方法,将任务添加进队列中
3.2 什么是多线程
线程:
多线程:
一个CPU反复在多个线程间切换,就好像多个线程可以并列执行一样,而在具有多个CPU核的情况下,就可以真的提供多个CPU核并行执行多个线程了
多线程问题:
数据竞争、死锁、消耗大量内存
3.3 GCD的API
Dispatch Queue
:执行处理的等待队列,分两种
Serial DispatchQueue
:串行队列 等待现在执行中处理结束
Concurrent Dispatch Queue
:并行队列 不等待现在执行中处理结束
Dispatch Queue
和线程的关系:
主线程中的队列是Main Dispatch Queue
,因为主线程只有一个,所以Main Dispatch Queue
自然就是 Serial Dispatch Queue
(我的理解:队列是用来派发任务的,而线程是用来处理任务的)
一旦生成Serial DispatchQueue
并追加处理,系统对于一个Serial DispatchQueue
就只生成并使用一个线程。如果生成2000个Serial DispatchQueue
,那么就生成2000个线程。所以Serial DispatchQueue
的生成个数应当仅限所必须的数量。如果过多使用多线程,就会大量消耗内存,引起大量的上下文切换,大幅度降低系统的响应性能。
XNU内核决定Concurrent Dispatch Queue
应该使用的线程数量
得到Dispatch Queue
的方法
- 创建
/*
参数一:线程名,一般那采用 逆序域名
参数二:NULL代表生成Serial DispatchQueue,生成Concurrent Dispatch Queue需指定为DISPATCH_QUEUE_CONCURRENT
*/
dispatch_queue_t myConcurrentDispatchQueue = dispatch_queue_create("com.example.gcd.myConcurrentDispatchQueue",DISPATCH_QUEUE_CONCURRENT);
注意:对于最低sdk版本>=iOS6.0来说,GCD对象已经纳入了ARC的管理范围,我们就不需要再手工调用 dispatch_release
了
- 获取系统标准提供的
Dispatch Queue
Main Dispatch Queue
属于Serial DispatchQueue
dispatch_queue_t mainDispatchQueue = dispatch_get_main_queue();
Global Dispatch Queue
所有的应用程序都能使用的Concurrent Dispatch Queue
dispatch_queue_t globalDispatchQueueHigh = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH,0);
Global Dispatch Queue
的4个执行优先级:
高优先级:DISPATCH_QUEUE_PRIORITY_HIGH
默认优先级:DISPATCH_QUEUE_PRIORITY_DEFAULT
低优先级:DISPATCH_QUEUE_PRIORITY_LOW
后台优先级:DISPATCH_QUEUE_PRIORITY_BACKGROUND
3.2.4 变更队列的优先级和执行层次dispatch_set_target_queue
变更队列优先级
dispatch_queue_t mySerialDispatchQueue = = dispatch_queue_create("com.example.gcd.mySerialDispatchQueue",NULL);
dispatch_queue_t globalDispatchQueueBackground = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND,0);
// 变更mySerialDispatchQueue的优先级,使之和globalDispatchQueueBackground相同
dispatch_set_target_queue(mySerialDispatchQueue,globalDispatchQueueBackground);
变更执行层次
如果在多个Serial Dispatch Queue
中用dispatch_set_target_queue
函数指定目标为某一个Serial Dispatch Queue
,那么原先应该并行执行的多个Serial Dispatch Queue
,在目标Serial Dispatch Queue
上只能同时执行一个处理。
3.2.5 指定时间追加到Dispatch Queue
,dispatch_after
/*
dispatch_time() 用于计算相对时间
第一个参数:指定开始时间
第二个参数:NSEC_PER_SEC 秒 ,NSEC_PER_MSEC 毫秒
*/
dispatch_time_t time = dispatch_time(DISPATCH_TIME_NOW,3ull * NSEC_PER_SEC);
dispatch_after(time,dispatch_get_main_queue(),^{
NSLog(@"waited at least three seconds.");
})
// 用于计算绝对时间
dispatch_walltime
注意:dispatch_after
并不是在指定时间后执行处理,而是在指定时间追加处理到Dispatch Queue
3.2.6 Dispatch Group
在追加到Dispatch Queue
中的多个处理全部结束后,想执行结束处理
dispatch_quque_t queue
dispatch_group_notify(group,dispatch_get_main_queue(),^{
NSLog()@"done";
});
// 相比dispatch_group_notify多了一个超时时间
dispatch_group_wait
3.2.7 dispatch_barrier_async
3.2.8 dispatch_sync
串行队列中(包括主队列),同步嵌套会造成死锁
dispatch_barrier_sync
3.2.9 dispatch_apply
代替for循环