块(block)的内部结构:
43BBDFA9-9F5E-488A-9808-A723854DDE5B.pngInvoke-> 函数指针,函数原型至少要接收一个void*型的参数,此参数代表块,块其实就是一种代替函数指针的语法结构
descriptor变量是指向结构体的指针,每个块里都包含此结构体,声明了块的整体大小,还声明了copy和dispose这两个函数对应的指针函数
块还会把所捕获的所有变量都拷贝一份(拷贝指针变量)
-
技巧二十六:块的使用注意
1.块只在定义它的那个范围内{ }有效,如果需要出了作用域仍旧可以使用,那么需要copy,将块从栈拷贝到堆
2.除了“栈块”和“堆块”外,还有全局块,全局块在编译期就已经完全确定,不会捕捉任何状态,运行时也不会有状态来参与
3.用typedef给块起别名,根据功能的不同,相同的参数的块也应该起不同的别名
-
技巧二十七:用handle块降低代码的分散程度
1.创建对象的时候可以用内联的handle块将部分业务逻辑连接在一块
2.可以由API设计者指定线程
-
技巧二十八:多用派发队列,少用同步锁
情景:多个线程要执行同一份代码
1.在GCD出现以前用的同步锁(不推荐,影响性能)
@synchronized (self) {
//doSomeThing
}
2.NSLock(可以,但是可能会出现死锁)
NSLock *lock = [[NSLock alloc]init];
[lock lock];
//doSomeThing
[lock unlock];
3.NSRecursiveLock(递归锁)(可以,但是可能会出现死锁)
4.GCD(同步串行)(推荐)
-
技巧二十九:少用perforselect,多用GCD
1.动态执行选择子,在内存管理上有疏失,ARC编译器不能在适当的地方插入内存管理方法
- 参数(最多两个)和返回值有限制(返回值必须为对象)
-
技巧三十: 掌握GCD及操作队列的使用时机
使用NSOperationQueue相对GCD的优势
1.取消队列,GCD的模式类似“安排好任务以后就不管了”(fire and forget),GCD中如果真要取消要写应用层代码,而操作队列已经帮我们写好了cancel,不过已经启动的任务无法取消
2.设置依赖关系
3.通过KVC观察可以更为精细的控制对象所要执行的任务(isFinish、isCancel)
4.操作的优先级 优于 线程的优先级
5.对象可以携带信息,自定义方法,在代码中多次使用,符合软件开发中不重复原则(DRY)
-
技巧三十一: 通过调度组机制,根据系统资源状况来执行任务
GCD调度组(dispatch group)其中最重要,最值得注意的用法就是: 将要并发执行的多个队列合并成一组,于是调用者就能知道何时这些任务才能全部执行完毕
// 队列(决定任务是否需要互相等待执行)跟线程没有必然联系,队列决定了任务的执行方式,线程是任务的执行通道
将队列添加到调度组
dispatch_group_async(group, queue,block)
监听调度组内的任务执行完毕
dispatch_group_notify(group, queue,block)
-
技巧三十二: 通过dispatch_once,创建线程安全的单例
+(instancetype)sharedInstance{
static People *sharedInstance = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
sharedInstance = [[People alloc]init];
});
return sharedInstance;
}
网友评论