1、在使用block前需要对block指针做判空处理。

不判空直接使用,一旦指针为空直接产生崩溃。

  1. if (!self.isOnlyNet) {
  2. if (succBlock == NULL) { //后面使用block之前要先做判空处理
  3. return;
  4. }
  5. id data = [NSKeyedUnarchiver unarchiveObjectWithFile:[self favoriteFile]];
  6. if ([data isKindOfClass:[NSMutableArray class]]) {
  7. succBlock(data,YES);
  8. }else{
  9. succBlock(nil,YES);
  10. }
  11. }
2、在MRC的编译环境下,block如果作为成员参数要copy一下将栈上的block拷贝到堆上(示例见下,原因参考

3、在block使用之后要对,block指针做赋空值处理,如果是MRC的编译环境下,要先release掉block对象。

block作为类对象的成员变量,使用block的人有可能用类对象参与block中的运算而产生循环引用。

将block赋值为空,是解掉循环引用的重要方法。(不能只在dealloc里面做赋空值操作,这样已经产生的循环引用不会被破坏掉)

  1. typedef void(^SuccBlock)(id data);
  2. @interface NetworkClass {
  3. SuccessBlock _sucBlock;
  4. }
  5. @property (nonatomic,assign)BOOL propertyUseInCallBack;
  6. - (void) requestWithSucBlock: (SuccessBlock) callbackBlock;
  7. @end
  8.  
  9. @implementation NetworkClass
  10. - (void) requestWithSucBlock: (SuccessBlock) callbackBlock {
  11. _sucBlock = callbackBlock;//MRC下:_sucBlock = [callbackBlock copy]; 不copy block会在栈上被回收。
  12. }
  13.  
  14. - (void) netwrokDataBack: (id) data {
  15. if (data != nil && _sucBlock != NULL) {
  16. _sucBlock(data);
  17. }
  18. //MRC下:要先将[_sucBlock release];(之前copy过)
  19. _sucBlock = nil; //Importent: 在使用之后将Block赋空值,解引用 !!!
  20. }
  21. @end
  22.  
  23. //=======================以下是使用方===========================
  24. @implementation UserCode
  25. - (void) temporaryNetworkCall
  26. {
  27. NetworkClass *netObj = [[NetworkClass alloc] init];
  28. netObj.propertyUseInCallBack = NO;
  29. [netObj requestWithSucBlock: ^(id data) {
  30. //由于block里面引用netObj的指针所以这里产生了循环引用,且由于这个block是作为参数传入对象的,编译器不会报错。
  31. //因此,NetworkClass使用完block之后一定要将作为成员变量的block赋空值。
  32. if (netObj.propertyUseInCallBack == YES) {
  33. //Do Something...
  34. }
  35. }];
  36. }
  37. @end

还有一种改法,在block接口设计时,将可能需要的变量作为形参传到block中,从设计上解决循环引用的问题。

如果上面Network类设计成这个样子:

  1. @class NetowrkClass;
  2. typedef void(^SuccBlock)(NetworkClass *aNetworkObj, id data);
  3. @interface NetworkClass
  4. //...
  5. @end
  6. @implementation NetworkClass
  7. @end
  8.  
  9. @implementation UserCode
  10. - (void) temporaryNetworkCall
  11. {
  12. NetworkClass *netObj = [[NetworkClass alloc] init];
  13. netObj.propertyUseInCallBack = NO;
  14. [netObj requestWithSucBlock: ^(NetworkClass *aNetworkObj, id data) {
  15. //这里参数中已经有netObj的对象了,使用者不用再从block外引用指针了。
  16. if (aNetworkObj.propertyUseInCallBack == YES) {
  17. //Do Something...
  18. }
  19. }];
  20. }
  21. @end

4、使用方将self或成员变量加入block之前要先将self变为__weak

5、在多线程环境下(block中的weakSelf有可能被析构的情况下),需要先将self转为strong指针,避免在运行到某个关键步骤时self对象被析构。

第四、第五条合起来有个名词叫weak–strong dance,来自于2011 WWDC Session #322 (Objective-C Advancements in Depth)

以下代码来自AFNetworking,堪称使用weak–strong dance的经典。

  1. __weak __typeof(self)weakSelf = self;
  2. AFNetworkReachabilityStatusBlock callback = ^(AFNetworkReachabilityStatus status) {
  3. __strong __typeof(weakSelf)strongSelf = weakSelf;
  4. strongSelf.networkReachabilityStatus = status;
  5. if (strongSelf.networkReachabilityStatusBlock) {
  6. strongSelf.networkReachabilityStatusBlock(status);
  7. }
  8. };
Review一下上面这段代码,里面玄机不少。

第一行:__weak __typeof(self)weakSelf = self;

如之前第四条所说,为防止callback内部对self强引用,weak一下。

其中用到了__typeof(self),这里涉及几个知识点:

a. __typeof、__typeof__、typeof的区别

恩~~他们没有区别,但是这牵扯一段往事,在早期C语言中没有typeof这个关键字,__typeof、__typeof__是在C语言的扩展关键字的时候出现的。

typeof是现代GNU C++的关键字,从Objective-C的根源说,他其实来自于C语言,所以AFNetworking使用了继承自C的关键字。

b.对于老的LLVM编译器上面这句话会编译报错,所以在很早的ARC使用者中流行__typeof(&*self)这种写法,原因如下

大致说法是老LLVM编译器会将__typeof转义为 XXX类名 *const __strong的__strong和前面的__weak关键字对指针的修饰又冲突了,所以加上&*对指针的修饰。

第三行:__strong __typeof(weakSelf)strongSelf = weakSelf;

按照之前第五条的说法给转回strong了,这里__typeof()里面写的是weakSelf,里面写self也没有问题,因为typeof是编译时确定变量类型,所以这里写self 不会被循环引用。

第四、五、六行,如果不转成strongSelf而使用weakSelf,后面几句话中,有可能在第四句执行之后self的对象可能被析构掉,然后后面的StausBlock没有执行,导致逻辑错误。

最后第五行,使用前对block判空。

写在最后,阅读好的开源库源码是提高个人水平的一个很好途径,看见不懂的地方去查去摸索会得到更多。

参考:

http://blog.csdn.net/fhbystudy/article/details/17350951

http://stackoverflow.com/questions/10892361/generic-typeof-for-weak-self-references

http://stackoverflow.com/questions/14877415/difference-between-typeof-typeof-and-typeof-objective-c

http://rocry.com/2012/12/18/objective-c-type-of/

http://fuckingblocksyntax.com/ 这是个工具网站,我每次写block的时候都会用到。

(转)关于block使用的5点注意事项的更多相关文章

  1. [好文要转]【关于block使用的5点注意事项】

    1.在使用block前需要对block指针做判空处理. 不判空直接使用,一旦指针为空直接产生崩溃. if (!self.isOnlyNet) { if (succBlock == NULL) { // ...

  2. 关于block使用的5点注意事项

    1.在使用block前需要对block指针做判空处理. 不判空直接使用,一旦指针为空直接产生崩溃. if (!self.isOnlyNet) { if (succBlock == NULL) { // ...

  3. 关于block使用的几点注意事项

    1.在使用block前需要对block指针做判空处理. 不判空直接使用,一旦指针为空直接产生崩溃. if (!self.isOnlyNet) { if (succBlock == NULL) { // ...

  4. ios开发之block的使用,及注意事项

    转自:http://my.oschina.net/u/1432769/blog/390401 Block作为C语言的扩展,并不是高新技术,和其他语言的闭包或lambda表达式是一回事.需要注意的是由于 ...

  5. Objective-C( block的使用)

    block block用来保存一段代码 block的标志:^ block跟函数很像:可以保存代码.有返回值.有形参.调用方式跟调用方法一样 block内部可以访问外面的变量 默认情况下,block内部 ...

  6. iOS之block

    1. Block的声明和线程安全Block属性的声明,首先需要用copy修饰符,因为只有copy后的Block才会在堆中,栈中的Block的生命周期是和栈绑定的,可以参考之前的文章(iOS: 非ARC ...

  7. C 【block类型全方位详解】

    ------------------------------------------- block变量的概念 #import <Foundation/Foundation.h> int m ...

  8. ios开发 block语句块

    ios开发 block语句块 1.block 理解为匿名函数 2.block变量的定义 //定义block变量,^表示定义block //技巧:函数名左右加括号,在函数名前面在加^ void (^bl ...

  9. 讲述Sagit.Framework解决:双向引用导致的IOS内存泄漏(下)- block中任性用self

    前言: 在处理完框架内存泄漏的问题后,见上篇:讲述Sagit.Framework解决:双向引用导致的IOS内存泄漏(中)- IOS不为人知的Bug 发现业务代码有一个地方的内存没释放,原因很也简单: ...

随机推荐

  1. 小组ITalk网站开发中使用到的一些技巧

    ----->Display属性和Visibility属性:一个清除内容和框体,另一个只清除内容而保留窗体: $('#abc').css({ 'font-size' : '12px', '-web ...

  2. 原生js实现轮播图原理

    轮播图的原理1.图片移动实现原理:利用浮动将所有所有照片依次排成一行,给这一长串图片添加一个父级的遮罩,每次只显示一张图,其余的都隐藏起来.对图片添加绝对定位,通过控制left属性,实现照片的移动. ...

  3. 【上传-下载】-jmeter工具

    上 传 ================================================================================================ ...

  4. java字符转义

    之前对java字符转义这一块稍作了解,在这里理理自己主观浅显的理解 这里会谈谈字符编码的是另一种问题和转义没有关系 以下面代码做分析 System.out.println("a". ...

  5. 一种跨平台的C++遍历目录的方法

    参考了网络上各路大神的实现方法.主要使用了io.h库 #include <iostream> #include <cstring> #include <io.h> ...

  6. CsvHelper文档-2读

    CsvHelper文档-2读 这个库默认不需要做任何设置就可以很容易的使用它.如果你的类属性名称直接匹配csv的标题名称,那么可以按照下面的实例来用: (以下所有的代码都需要引用using csvhe ...

  7. Java VisualVM使用

    Java VisualVM Java VisualVM官网 Java VisualVM介绍 Java VisualVM is a tool that provides a visual interfa ...

  8. Docker Remote API v1.24

    1. Brief introduction The Remote API has replaced rcli. The daemon listens on unix:///var/run/docker ...

  9. 某即时通信工具与RMS结合

    某客户内部使用及时通信工具与RMS相结合,如果客户使用了海外版Office 365E3可以直接在手机端使用Office app打开. 如果客户没有使用海外版Office 365E3的版本,需要结合本地 ...

  10. [git] Git in Practice

    Work flow with git and github Work with Remotes Check the current status git status Check the latest ...