iOS-Block的总结
来源:互联网 发布:薛家 知乎 编辑:程序博客网 时间:2024/05/22 16:59
前言: 前面学习了那么多block的知识, 其实就为了解决项目中的几个问题
1. ARC 与 MRC下__block的区别
2. __block 和 __weak的区别
3. block内嵌的注意事项
4. block使用场景中的block块中, 引用self是否使用__weak或__block
1. ARC 与 MRC下__block的区别
- 在 MRC 下,使用 __block 说明符也可以避免循环引用。因为当 block 从栈拷贝到堆时,__block 对象类型的变量不会被 retain,没有 __block 说明符的对象类型的变量则会被 retian
- 在ARC下, 使用__block会retain修饰的对象类型, 防止循环引用可使用__weak(iOS5.0才有)或__unsafe_unretain
2. __block 和 __weak的区别
__weak specifies a reference that does not keep the
referenced object alive. A weak reference is set to nil when
there are no strong references to the object.
使用了__weak修饰符的对象,作用等同于定义为weak的property。自然不会导致循环引用问题,因为苹果文档已经说的很清楚,当原对象没有任何强引用的时候,弱引用指针也会被设置为nil。
因此,__block和__weak修饰符的区别其实是挺明显的:
- ARC下__weak修饰的对象在改对象销毁后也会被销毁, 并置为nil, 但是__block修饰的对象在该对象销毁后仍然存在, 所以容易造成循环引用
- __block不管是ARC还是MRC模式下都可以使用,可以修饰对象,还可以修饰基本数据类型。
- __weak只能在ARC模式下使用,也只能修饰对象(NSString),不能修饰基本数据类型(int)。
- __block对象可以在block中被重新赋值,__weak不可以。
- __block对象在ARC下可能会导致循环引用,非ARC下会避免循环引用,__weak只在ARC下使用,可以避免循环引用。
PS:__unsafe_unretained
修饰符可以被视为iOS SDK 4.3以前版本的__weak的替代品,不过不会被自动置空为nil。所以尽可能不要使用这个修饰符。
3. block内嵌block的注意事项
在block里面使用block,比如在GCD的block里内嵌另一个block。因为GCD本身会拷贝传入dispatch_queue中的block,内嵌的block也会同时被拷贝:
When you copy a block, any references to other blocks from within that block are copied if necessary—an entire tree may be copied (from the top). If you have block variables and you reference a block from within the block, that block will be copied.
另外当block作为NSDictionary的key时,这些key都是默认copy的。原因很简单:NSDictionary是通过key hash拿到的值进行查询,如果不对key进行拷贝,则在进行查询时会因为key的变化而导致查询失败。(所以也不太推荐拿一些复杂易变的对象当作NSDictionary的key)
4. block使用场景中的block块中, 引用self是否使用__weak或__block
AFN GCD Masonry等
将Block作为参数传给AFN, dispatch_async, Masonry时,系统会将Block拷贝到堆上,如果Block中使用了实例变量,还将retain self,因为AFN, dispatch_async, Masonry并不知道self会在什么时候被释放,为了确保系统调度执行Block中的任务时self没有被意外释放掉,AFN, dispatch_async, Masonry必须自己retain一次self,任务完成后再release self。但这里使用__weak,使AFN, dispatch_async, Masonry没有增加self的引用计数,这使得在系统在调度执行Block之前,self可能已被销毁,但系统并不知道这个情况,导致Block被调度执行时self已经被释放导致crash。
//#import "Person.h"- (void)say { __weak typeof(self) weakSelf = self; dispatch_time_t popTime = dispatch_time(DISPATCH_TIME_NOW, (int64_t)(5 * NSEC_PER_SEC)); dispatch_after(popTime, dispatch_get_main_queue(), ^(void){ NSLog(@"%@", weakSelf); });}//#import "ViewController.h"//#import "Person.h"Person *person = [[Person alloc] init];[person say];
这里用dispatch_after模拟了一个异步任务,10秒后执行Block。但执行Block的时候Person *person已经被释放了,打印为 2016-03-15 15:14:16.048 TestBlock[3588:143295] (null)
,
导致crash。解决办法是不要使用__weak
控制器间
…
5. Block实例注意
使用__block与不使用__block的比较:
typedef long (^BlkSum)(int, int); int base = 100; BlkSum sum = ^ long (int a, int b) { return base + a + b; }; base++; printf("%ld\n",sum(1,2)); // result: 103 printf("%d\n",base); // result: 101
typedef long (^BlkSum)(int, int); __block int base = 100; BlkSum sum = ^ long (int a, int b) { return base + a + b; }; base++; printf("%ld\n",sum(1,2)); // result: 104 printf("%d\n",base); // result: 101
- 使用__block修饰变量时,将取变量
此刻运行时的值
,而不是定义时的值。这个例子中,执行sum(1,2)时,base将取base++之后的值,也就是101,再执行 base+a+b,运行结果是104。执行完Block时,base已经变成101了。- 不使用__block修饰变量时,将取变量定义时的值。这个例子中,执行sum(1,2)时是100,再执行 base+a+b,运行结果是103。
在 ARC 开启的情况下,将只会有 NSConcreteGlobalBlock 和NSConcreteMallocBlock类型的 block。
原本的 NSConcreteStackBlock 的 block 会被 NSConcreteMallocBlock 类型的 block 替代, 因此使用strong和copy修饰block属性区别不大, 但是官方还是建议使用copy修饰
- iOS-block的总结
- iOS-Block的总结
- ios中block的学习总结
- IOS中关于Block的用法总结
- iOS block 总结
- iOS block使用总结
- iOS中Block总结
- iOS总结 - Block
- Block编程总结【iOS】
- iOS面试题总结---block
- iOS block 基本用法总结
- IOS开发之我对block的认识总结
- ios block回调的理解和总结
- iOS Block在ARC/非ARC下的使用总结
- iOS Block在ARC/非ARC下的使用总结
- iOS Block在ARC/非ARC下的使用总结
- iOS中关于block使用的一些总结
- iOS 关于页面回调传值的总结(delegete、block)
- Class类文件加载机制
- Qt例子一 AddressBook测试学习
- Java day02 类型转换(2)
- POJ 1325 Machine Schedule(二分匹配-hungary)
- @SuppressWarnings("resource")
- iOS-Block的总结
- Java类文件的基本结构
- 归并排序
- 黑大助手后端和Android端开发笔记
- GOF23设计模式
- java day02 for循环的进一步理解
- Java 系统高并发解决方案(转载)
- 职责链模式
- 客户端协议处理框架