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

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

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

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

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

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

typedef void(^SuccBlock)(id data);
@interface NetworkClass {
SuccessBlock _sucBlock;
}
@property (nonatomic,assign)BOOL propertyUseInCallBack;
- (void) requestWithSucBlock: (SuccessBlock) callbackBlock;
@end @implementation NetworkClass
- (void) requestWithSucBlock: (SuccessBlock) callbackBlock {
_sucBlock = callbackBlock;//MRC下:_sucBlock = [callbackBlock copy]; 不copy block会在栈上被回收。
} - (void) netwrokDataBack: (id) data {
if (data != nil && _sucBlock != NULL) {
_sucBlock(data);
}
//MRC下:要先将[_sucBlock release];(之前copy过)
_sucBlock = nil; //Importent: 在使用之后将Block赋空值,解引用 !!!
}
@end //=======================以下是使用方===========================
@implementation UserCode
- (void) temporaryNetworkCall
{
NetworkClass *netObj = [[NetworkClass alloc] init];
netObj.propertyUseInCallBack = NO;
[netObj requestWithSucBlock: ^(id data) {
//由于block里面引用netObj的指针所以这里产生了循环引用,且由于这个block是作为参数传入对象的,编译器不会报错。
//因此,NetworkClass使用完block之后一定要将作为成员变量的block赋空值。
if (netObj.propertyUseInCallBack == YES) {
//Do Something...
}
}];
}
@end

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

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

@class NetowrkClass;
typedef void(^SuccBlock)(NetworkClass *aNetworkObj, id data);
@interface NetworkClass
//...
@end
@implementation NetworkClass
@end @implementation UserCode
- (void) temporaryNetworkCall
{
NetworkClass *netObj = [[NetworkClass alloc] init];
netObj.propertyUseInCallBack = NO;
[netObj requestWithSucBlock: ^(NetworkClass *aNetworkObj, id data) {
//这里参数中已经有netObj的对象了,使用者不用再从block外引用指针了。
if (aNetworkObj.propertyUseInCallBack == YES) {
//Do Something...
}
}];
}
@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的经典。

__weak __typeof(self)weakSelf = self;
AFNetworkReachabilityStatusBlock callback = ^(AFNetworkReachabilityStatus status) {
__strong __typeof(weakSelf)strongSelf = weakSelf;
strongSelf.networkReachabilityStatus = status;
if (strongSelf.networkReachabilityStatusBlock) {
strongSelf.networkReachabilityStatusBlock(status);
}
};
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使用的几点注意事项

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

  3. (转)关于block使用的5点注意事项

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

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

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

  5. block的内部实现

    主要内容: 一.block相关的题目 二.block的定义 三.block的实现 四.捕获自动变量值 五.block存储区域 六.截获对象 一.block相关的题目 这是一篇比较长的博文,前部分是bl ...

  6. block的语法

    主要内容: 1. 开始使用block(Getting Started with Blocks) 2. block概念综述(Conceptual Overview) 3. 声明和创建block(Decl ...

  7. Hadoop 文件的数量怎么比block的数量多?

    Total files:    23 Total symlinks:        0 Total blocks (validated):    22 (avg. block size 117723 ...

  8. iOS中block实现的探究

    [0. Brief introduction of block] Block是iOS4.0+ 和Mac OS X 10.6+ 引进的对C语言的扩展,用来实现匿名函数的特性. 用维基百科的话来说,Blo ...

  9. ObjectiveC中的block用法解析

    Block Apple 在C, Objective-C,C++加上Block这个延申用法.目前只有Mac 10.6 和iOS 4有支持.Block是由一堆可执行的程序组成,也可以称做没有名字的Func ...

随机推荐

  1. HDOJ 1004 Let the Balloon Rise

    Problem Description Contest time again! How excited it is to see balloons floating around. But to te ...

  2. 使用Cobbler无人值守安装CentOS6.5(一)

    Cobbler是一个快速网络安装linux的服务,而且在经过调整也可以支持网络安装windows.该工具使用python开发,小巧轻便(才15k行代码),使用简单的命令即可完成PXE网络安装环境的配置 ...

  3. vs2013 括号自动配对样式设置

     在做公司一个项目的时候,需要用到VS2013编辑器,用了之后感觉有点不太爽. 在js文件里定义了方法之后,由于方法比较长,写完之后再回来看就有些不方便,尤其是方法里还有几个判断,后人再看的时候会有些 ...

  4. 商品条形码(JBarcode)

    之前没有使用过这个,现在使用JBarcode生成商品条形码,工作之前的准备工作: Eclipse:Eclipse Java EE IDE for Web Developers.Version: Hel ...

  5. 谷歌 HTML/CSS 规范 2016-12-30

    背景 这篇文章定义了 HTML 和 CSS 的格式和代码规范,旨在提高代码质量和协作效率. 通用样式规范 协议 省略图片.样式.脚本以及其他媒体文件 URL 的协议部分(http:,https:),除 ...

  6. oracle表分区、表分析及oracle数据泵文件导入导出开心版

    1.先说oracle表分区是什么吧,这样吧我们来举个桃子,栗子太小,我们就不举了,我们来举个桃子. 你有500万份文件,你要把他存在磁盘上,好嘛,我们就一个文件夹,500万分文件在那儿杵着,我们想找到 ...

  7. 【转】破解Source Insight 3.5.0072过程 附:安装软件+注册机

    转载地址:http://blog.csdn.net/qs_hud/article/details/8884867 注册机及软件下载地址:http://download.csdn.net/detail/ ...

  8. Volley 实现原理图

    1.启动requestQueue 2. 添加请求 3. 启动cacheDispatcher 4.启动networkDispatcher 5. 数据分发

  9. 总结一下今天做的unity面试题(一):刚体的点击事件

    按照需求,由于要模拟丧尸被击中的效果,不能使用CharactorControll组件,只能使用rigidbody组件. 首先在场景上摆好僵尸和相机的位置,这里就不给相机加脚本了,直接固定住. 然后给丧 ...

  10. 关于el jstl

    requestScope表示从request范围内取得.其他的还有sessionScope, pageScope和applicationScope,分别对应4种属性范围.而如果直接写${passwor ...