1, 块Block 是C, C++, OC 中的词法闭包
2,块可以接受参数,可以返回值
3, 块可以分配字栈上,也可以分配在堆上,也可以是全局的。分配在栈上的块可以拷贝在堆里,这样的话,就和标准的OC对象一样,具备了引用计数
---- 定义块的时候,其所占的内存区域是分配在栈中
执行Copy 方法后,复制到堆上了
38,为常用的块类型创建typedef
1,以typedef重新定义块类型,可令块变量用来更加简单
2,定义新类型时,应遵从先用的命名习惯,不要使用其名称与别的类型相冲突
3, 可以为同一块签名定义多个类型别名,如果要重构的代码用了块类型的某个别名,那么只需修改相应的块签名即可,无需改动其他typedef
39,用hander块降低代码分散程度
1, 在创建对象的时候,可以使用内联的hander块江相关业务逻辑一并说明
2, 在有多个实例监控时,如果采用委托模式,那么经常需要根据传入的对象来切换,而若使用hander块来实现,则可以直接将块与相关对象放在一起
3,设计API 时,如果用到了hadner块,那么可以增加一个参数,是调用者可通过此参数来决定应该安排在哪个队列执行
40,用块应用其所属对象时,不用出现保留环
1, 如果块所捕获的对象直接或间接的保留了块本身,那么就要当心保留环的问题
2, 一定要找个适当的时机解除保留环,而不能把责任推给API调用者
在API实现的方法里,如果调用了实例变量,就会出现保留环。打破保留环的方法是,在适当的时候,= nil
41, 多用派发队列,少用同步锁
1,派发队列可用来表述同步语义,这种做法要比使用 @syncheonized块 或NSLock对象更加简单
2,将同步和异步派发结合起来,可以实现与普通加锁机制一样的同步行为,而这么做却不会阻塞执行异步派发的线程
3, 使用同步队列和栅栏块,可以另同步更加高效
实例变量
42,多用GCD,少用performSelector方法
1,performSelector 系列方法在内存管理方面容易有疏失。它无法确定要执行的选择子具体是什么,因而ARC编译器也就无法插入适当的内存管理方法
2,performSelector系列方法所能处理的选择子太过局限了,选择子的返回类型及发送给参数的方法的参数个数都受到限制
3,如果想把任务放在另一个线程中执行, 那么最好不要使用performSelector系列方法,而应该把任务封装在块里,然后调用GCD的相关方法实现
43,掌握GCD及操作队列的使用时机
1,在解决多线程和任务管理问题时,派发队列(GCD)并非唯一方法
2,操作队列(NSOperation)提供了一套高层的 OC API,能实现纯GCD 所具备的绝大部分功能,而且还能完成更为复杂的操作,那些操作若改用GCD实现,则需要另外编写代码
44,通过Dispatch Group机制,更具系统资源情况来执行
dispatch_queue_t queue = dispatch_get_global_queue(0, 0);
dispatch_group_t group = dispatch_group_create();
void(^block1)() = ^(){
for(inti = 0; i < 1000; i++) {
NSLog(@"%@--- > block1 + %d", [NSThread currentThread], i);
}
};
void(^block2)() = ^(){
for(inti = 0; i < 1000; i++) {
NSLog(@"%@--- >--- > block2 + %d", [NSThread currentThread], i);
}
};
void(^block3)() = ^(){
for(inti = 0; i < 1000; i++) {
NSLog(@"%@--- >--- >--- > block3 + %d", [NSThread currentThread], i);
}
};
dispatch_group_async(group, queue, block1);
dispatch_group_async(group, queue, block2);
dispatch_group_async(group, queue, block3);
dispatch_group_notify(group, dispatch_get_global_queue(0, 0), ^{
NSLog(@"%@结束了", [NSThread currentThread]);
});
45,使用dipatch_once来执行只需运行一次的线程安全代码
1, 经常需要编写‘只需执行一次的线程安全代码’。通过GCD所提供的dispatch_once函数,很容易就能实现此功能
2,编译应该声明在static 或者 global 作用域中,这样的话,在把只需执行一次的块传给 dispatch_once 函数,传进去的标记也是相同的
+(instancetype)shareManager
{
static dispatch_once_tpred;
static BluetoothLEService* manager =nil;
dispatch_once(&pred, ^{
manager = [[BluetoothLEService alloc] init];
manager.arrFilterName= [@[@"WATER-",@"Cupcare-"]mutableCopy];
});
return manager;
}
46, 不用使用 dispatch_get_current_queue
1, dispatch_get_current_queue 函数的行为常常与开发者的预期不同。此函数已经废弃,只用做调试使用
2, 由于派发队列是按层级来组织的,所有无法单用某个队列对象来描述‘当前队列‘这个概念
3, dispatch_get_current_queue 函数用于解决由不可重入的代码所引起的死锁,然后能用这个函数解决的问题,通常也能使用队列特定数据’来解决