首页 > 其他分享 >关于Block的使用和5点注意事项

关于Block的使用和5点注意事项

时间:2022-11-28 17:03:49浏览次数:41  
标签:__ NetworkClass self void typeof 注意事项 Block block 关于


一、概念

首先需要了解的是Block是一个代码块,是一个变量的形式存在的。

二、构成了解

我们需要在函数中声明block,因为是变量的形式,而且存在静态变量形式

类型1:

 NSString* (^blocks)(NSString*)= ^(NSString *str)

    {

        //NSLog(@"this is :%@",str);

        return str;

    };

返回值类型是字符串,如同函数一样,返回值类型写在最前面

^blocks是声明一个代码块,名字叫做blocks

后面括号跟的是参数的类型,如果没有参数返回void,如果有多个参数类型,那么逗号分隔列出

等于号后面的是参数名列表。

因为写的是一个有返回值的block,所以需要return一个与返回值类型相同类型的值,这里返回的是参数字符串

类型2:

int (^david)(int)= ^(int num)

    {

        return num*5;

    };

这里的返回值类型是一个int,代码块名字叫做david,参数是一个int类型的变量

等于号后面是参数列表,执行的语句是return num *5这句话。

因为如上的两个例子都是有返回值的类型,那么我在调用的时候可以直接使用。

例如:

    NSLog(@"this is block:%@",blocks(@"hello"));

    NSLog(@"this is block:%d",blocks(5));

类型3:

void (^david)(void)= ^(void)

    {

            NSLog(@"I am a block code!");

    };

这里只是简单的执行了一句话,调用方法就是直接打印或者当作变量直接使用。

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



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

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



关于Block的使用和5点注意事项_ios



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);
}
}



关于Block的使用和5点注意事项_ios



2、在MRC的编译环境下,block如果作为成员参数要copy一下将栈上的block拷贝到堆上(示例见下, ​​原因参考​​)

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

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

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



关于Block的使用和5点注意事项_ios



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的使用和5点注意事项_ios



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

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



关于Block的使用和5点注意事项_ios



@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



关于Block的使用和5点注意事项_ios



 



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的经典。



关于Block的使用和5点注意事项_ios



__weak __typeof(self)weakSelf = self;
AFNetworkReachabilityStatusBlock callback = ^(AFNetworkReachabilityStatus status) {
__strong __typeof(weakSelf)strongSelf = weakSelf;
strongSelf.networkReachabilityStatus = status;
if (strongSelf.networkReachabilityStatusBlock) {
strongSelf.networkReachabilityStatusBlock(status);
}
};



关于Block的使用和5点注意事项_ios



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


标签:__,NetworkClass,self,void,typeof,注意事项,Block,block,关于
From: https://blog.51cto.com/u_15894905/5892259

相关文章

  • 云边端协同EasyCVR语音对讲配置的注意事项汇总
    EasyCVR视频融合云服务基于云边端一体化架构,具有强大的数据接入、处理及分发能力,平台支持海量视频汇聚管理,可提供视频监控直播、云端录像、云存储、录像检索与回看、智能告......
  • Easy系列各视频平台云台控制功能的使用注意事项汇总
    TSINGSEE青犀视频旗下Easy系列视频平台,比如EasyCVR、EasyNVR、EasyGBS等,均可支持对摄像头的云台控制,包括摄像头的焦距调整、方向调整等。在视频监控场景中,摄像头的云台控制......
  • EasyCVR电子放大功能的操作使用及注意事项
    EasyCVR平台基于云边端一体化架构,具有强大的数据接入、处理及分发能力。平台可在复杂的网络环境中,将分散的各类视频资源进行统一汇聚、整合、集中管理,可实现的视频功能包括:......
  • 关于页面输入框的字段限长问题,查询数据库字符集
    关于页面输入框的字段限长如果开发文档或者接口文档没有明确给出字段的限制长度,我们在写页面的时候需要自己去数据库查看字段长度以Oracle数据库为例如果Oracle的字符集......
  • 关于面向过程,面向对象,面向切面编程
    最近在学习spring的AOP,顺便把三种思想一起总结一下。仅代表个人理解,欢迎指正。首先是面向过程编程,在实现业务逻辑的时候,整理出业务流,然后细分成方法,编程实装。通......
  • 关于Compilation failed: internal java compiler error的解决方法(Idea)
    关于Compilationfailed:internaljavacompilererror的解决方法(Idea)idea编译项目时出现java:Compilationfailed:internaljavacompilererrorjava:编译失败:内部j......
  • 关于Vetur、Prettier、ESLint插件冲突配置问题
      网上关于Vetur、Prettier、ESLint插件的配置问题,零零散散,基本都是各种……,你懂的......
  • 关于交换机的VLAN技术你了解多少?
     VLAN(虚拟局域网)是对连接到的第二层交换机端口的网络用户的逻辑分段,不受网络用户的物理位置限制而根据用户需求进行网络分段。一个VLAN可以在一个交换机或者跨交换机实现。......
  • 关于final关键字的一些总结
    final关键字主要用在三个地方:变量、方法、类。1.对于一个final变量,如果是基本数据类型的变量,则其数值一旦在初始化之后便不能更改;如果是引用类型的变量,则在对其初始化之后便......
  • <六>关于虚函数和动态绑定
    问题:是不是虚函数的调用就一定是动态绑定?不是的1:在类的构造函数当中,调用虚函数,也是静态绑定(构造函数中对虚函数的调用不发生动态绑定)2:如果不是通过指针或者引用变......