美文网首页
block 处理

block 处理

作者: M_Baron | 来源:发表于2017-12-05 10:02 被阅读8次

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判空。 

相关文章

  • block 处理

    1、在使用block前需要对block指针做判空处理。 不判空直接使用,一旦指针为空直接产生崩溃。 复制代码 if...

  • NSURLSession发送GET-POST-DOWNLOAD请

    block方式处理返回结果: delegate方式处理返回结果:

  • [iOS]Block系列探究六 - __block变量和对象

    之前的文章[iOS]Block系列探究二 - 捕获变量谈论过__block是如何处理基础类型的局部变量使block...

  • 浅谈oc与Swift中闭包的使用

    ▍先看oc: 初始化block时,所使用的外部变量已经被处理完毕,而不是执行block时处理。 一般情况(没有__...

  • ios拓展34-block的5点注意

    1、在使用block前需要对block指针做判空处理。 2、在MRC的编译环境下,block如果作为成员参数要co...

  • iOS开发之利用Block逆向传值

    一、书写规范Block传值,需要注意的是,谁传值就需要定义Block,捕获方仅仅需要传递Block给传值方,并处理...

  • IOS_Block_注意事项

    1、在使用block前需要对block指针做判空处理 2.避免循环引用 block会飞内部的所有对象引用计数加1,...

  • block注意事项

    1、在使用block前需要对block指针做判空处理 2、block如果作为属性变量时,要copy一下,将栈上的b...

  • 工作笔记

    1、self在block里强引用怎么处理? 首先,在block外面声明一个弱引用对象__weak ViewCont...

  • Objective-C Block(闭包)实现

    Block的实质 Block我想写OC的都不会陌生,在项目中我们经常会使用block作为数据处理后的回调,例如通知...

网友评论

      本文标题:block 处理

      本文链接:https://www.haomeiwen.com/subject/gdeqixtx.html