iOS开发 Block的使用方法和规范,以及可能遇到的问题

时间:2022-03-09 20:43:42

常用Block,写一个文章来避免自己犯错 ,之后会不断补充Block的使用方式

1.什么是Block

  1. Block是一种多个文件之间的数据交互方式
    是Objective-C特有的一种数据类型
    它可以保存一段代码,在合适的时候取出来调用

  2. 常见格式

//不带参数,不带名称
^{

}

//带名称
void (^someBlock)() = ^{

}

//带参数带返回值
int (^addBlock)(int a, int b) = ^(int a, int b){
return a+b;
}
  1. 两种定义方式
@property (copy) void(^MyBlock)(void);

typedef void(^MyBlock)(void);//常用的block建立
@property (nonatomic, copy) MyBlock block;
  1. block在一些场合下需要用到copy,比如下边这段代码,如果在栈上if和else里会被释放
void (^block)();
if(xxx){
block = ^{
NSLog(@"1");
}
}else{
block = ^{
NSLog(@"2");
}
}
block();

这个时候我们需要用到copy把它放在堆上来,避免它被释放

void (^block)();
if(xxx){
block = [^{
NSLog(@"1");
} copy];
}else{
block = [^{
NSLog(@"2");
} copy];
}
block();
  1. 在属性中声明block用什么来修饰?strong和copy都一样

使用copy修饰block是MRC时期的遗留物,这在MRC时期是至关重要的事情,但是使用ARC的现在,strong是可以代替的,只是一个习惯问题而已。

block其实是一个对象,有和其他对象相同的一些特性和信息,看起来像是C语言里的函数

2.Block优缺点 ####

相比代理,Block更轻便简单,不需要定义代理,协议,可以直接使用
如果有很多相关方法,我们就需要使用代理,这样更方便管理
使用Block需要避免循环引用

3.Block循环引用 ####

  1. Block循环引用种类大概有三种,就不列举了,我们只需要知道如何避免循环引用就可以了

  2. 防止Self循环引用,当然括号里可以使任何对象,个人建议凡是Block中的对象都要使用 __weak

__weak typeof(self) weakSelf=self;
__weak TSController * weakCtl=Ctl;
  1. 在 block 中进行强引用防止被释放,一半多次使用的时候需要加strong,防止block没有跑完self被释放
    typeof(self) __strong strongSelf = weakSelf;
ViewController *bSelf = wSelf;

4.Block中修改局部变量需要使用__block 修饰 ####

  1. Block中修改局部变量需要使用__block
    Block修饰符在ARC中Copy和Strong一样的,在MRC中用Copy
    Block中有时候需要用到Strong

  2. 保证代码在执行到block中,self不会被释放,当block执行完后,会自动释放该strongSelf

分享一个大神的总结

5.Block常见用法(会不断补充) ####

  1. 在头文件中定义Block属性,进行值传递

    一般在View向Controller进行值传递的时候经常用到

定义

@property (strong,nonatomic)void (^TSHTToolCollectionCellBlock)(TSHTToolCollectionCell * cell);

实现

    __weak typeof(self) weakSelf = self;
[cell setTSHTToolCollectionCellBlock:^(TSHTToolCollectionCell * htcell)
{
NSString * msgString=[NSString stringWithFormat:@"%ld/9\n长按图片可以拖动排序",(weakSelf.imageSelectArray.count)];
weakSelf.msgLabel.text=msgString;
}];

调用

    if (self.TSHTToolCollectionCellBlock)
{
self.TSHTToolCollectionCellBlock(self);
}
  1. 定义带Block的方法

    涉及到线程的方法,我们需要回到主线程

- (void)clipImageComplete:(void (^)(UIImage * clipedImage))complete
{
__weak typeof(self) weakSelf = self;
dispatch_queue_t conQueue = dispatch_queue_create("concurrentQueue", DISPATCH_QUEUE_CONCURRENT);
dispatch_async(conQueue, ^
{
//开始画图
UIImage * clipedImage=[weakSelf clipImage];
dispatch_sync(dispatch_get_main_queue(), ^{
complete(clipedImage);
});
});
}

注意:分享一个宏定义 ####

#ifndef weakify
#if DEBUG
#if __has_feature(objc_arc)
#define weakify(object) autoreleasepool{} __weak __typeof__(object) weak##_##object = object;
#else
#define weakify(object) autoreleasepool{} __block __typeof__(object) block##_##object = object;
#endif
#else
#if __has_feature(objc_arc)
#define weakify(object) try{} @finally{} {} __weak __typeof__(object) weak##_##object = object;
#else
#define weakify(object) try{} @finally{} {} __block __typeof__(object) block##_##object = object;
#endif
#endif
#endif

#ifndef strongify
#if DEBUG
#if __has_feature(objc_arc)
#define strongify(object) autoreleasepool{} __typeof__(object) object = weak##_##object;
#else
#define strongify(object) autoreleasepool{} __typeof__(object) object = block##_##object;
#endif
#else
#if __has_feature(objc_arc)
#define strongify(object) try{} @finally{} __typeof__(object) object = weak##_##object;
#else
#define strongify(object) try{} @finally{} __typeof__(object) object = block##_##object;
#endif
#endif
#endif

使用时候直接在block外边@weakify(self),在block里边使用@strongify(self)