关于block的认识

2018-02-02  本文已影响3人  Carson_Zhu

前言

block是一种比较特殊的数据类型。它可以保存一段代码,在合适的时候取出来调用。

block的声明
typedef int(^myBlock)(int, int);

@interface Person : NSObject
@property (nonatomic, copy) myBlock myBlock;
@end
@property (nonatomic, copy) void (^callback)(NSString *name);
- (void)func:(int (^)(int, int))callback;
block的实现
self.carson.callback = ^NSString *(NSString *name) {
    NSLog(@"%@", name);
};
block的作用域

block需要注意的一个特性就是Variable Capturing,直译过来就是捕捉变量。block会将“捕捉”到的变量复制一份,然后对复制品进行操作。如果希望block作用域内可以修改外边的变量,可以使用__block

__block int i = 0;
self.carson.callback = ^NSString *(NSString *name) {
    NSLog(@"%@", name);
    i ++;
};
somePerson.callback(@"张三");
NSLog(@"i == %d", i);

打印结果:

2018-02-02 15:53:13.386997+0800 Block[6754:448733] i == 1
block的三种类型

怎么判断一个block所在的存储位置呢?

声明block属性的时候为什么用copy

使用copy修饰符的作用就是将block从栈区拷贝到堆区,复制到堆区的主要目的就是保存block的状态,延长其生命周期。因为block如果在栈上的话,其所属的变量作用域结束,该block就被释放掉。

不同类型的block使用copy方法的效果也不一样,如下所示:

block的循环引用

在使用block的时候,我们要特别注意循环引用的问题,先来看一个循环引用的例子:

@interface Person : NSObject
@property (nonatomic, copy) void (^callback)(NSString *name);
@property (nonatomic, assign) NSInteger age;
@end
@interface ViewController ()
@property (nonatomic, strong) Person *carson;
@end
self.carson.callback = ^void (NSString *name) {
    self.carson.age = 5;
};

在上面的代码中Person类声明了一个block属性,所以Person对象carsonblock有一个强引用。而在block内部又对carson进行了一次强引用,这样就形成了一个封闭的环,也就是我们经常说的强引用循环。由于其相互引用,内存不能够进行释放,就造成了内存泄漏的问题。

__weak解决循环引用
__weak typeof(self) weakSelf = self;
self.carson.callback = ^void (NSString *name) {
    weakSelf.carson.age = 5;
};

但是在并发执行的时候,block的执行是可以抢占的,而且对weakSelf指针的调用时序不同可以导致不同的结果,比如在一个特定的时序下weakSelf可能会变成nil,这个时候在执行doAnotherThing就会造成程序的崩溃。为了避免出现这样的问题,采用__strong的方式来进行避免,更改后的代码如下:

__weak typeof(self) weakSelf = self;
self.carson.callback = ^void *(NSString *name) {
    __strong typeof(weakSelf) strongSelf = weakSelf;
    strongSelf.carson.age = 5;
};

总结:

上一篇 下一篇

猜你喜欢

热点阅读