对iOS的Block简单理解

2019-11-10  本文已影响0人  雨天多久就

声明和使用Block

^操作符有两个作用:

int multiplier = 7;
int (^myBlock)(int) = ^(int num) {
    return num * multiplier;
};
image

直接使用Block

有很多场景下,我们不需要声明block就可以直接使用。
可以直接书写block的定义作为一个参数传递给函数

    [NetWorkTool testBlock:^{
        
    }];

__block标记变量

block可以直接使用和它处于相同作用域下的变量(高级别的变量,比如全局变量不仅可以使用,还可以直接修改),但是只能使用,无法修改。
给变量加上__block标识后,就可以进行修改了。

Block 和 变量

block内的变量会有五种对待方式:

对象 和 block变量

(这个很关键,block造成的内存泄漏问题一般都是这个原理)
当block被拷贝的时候,block内的对象变量会被强引用

dispatch_async(queue, ^{
    // instanceVariable is used by reference, a strong reference is made to self
    doSomethingWithObject(instanceVariable);
});

id localVariable = instanceVariable;
dispatch_async(queue, ^{
    /*
      localVariable is used by value, a strong reference is made to localVariable
      (and not to self).
    */
    doSomethingWithObject(localVariable);
});

循环引用相关例子

问题1: 下面这个例子,vc离开的时候能否正常被释放?
- (void)viewDidLoad {
    [super viewDidLoad];
    // Do any additional setup after loading the view.
    
    void(^MyTwoBlock)(void) = ^{
        [self view];
    };
    MyTwoBlock();
}
回答:可以正常释放。 因为MyTwoBlock虽然会对self进行强引用,但是viewDidload执行完毕后,block就释放掉了,所以没有引用环。

问题2: 下面的例子,vc离开的时候能否正常被释放?

- (void)viewDidLoad {
    [super viewDidLoad];
    // Do any additional setup after loading the view.
    
    void(^MyTwoBlock)(void) = ^{
        [self view];
    };
    self.kmjBlock = MyTwoBlock;
}
回答:会造成内存泄漏。因为self对MyTwoBlock有个强引用了。
问题3:属性设置成copy和strong有什么区别吗?
@property (nonatomic, strong) void(^kmjBlock)(void);//
@property (nonatomic, copy) void(^kmjBlock)(void);//
回答:没有区别。因为block是否在堆上是由系统直接完成的。如果一个block内部访问了外部的变量,就会自动被拷贝到堆上。所以这里用strong修饰和copy修饰,其实都只是增加了一个强引用。

block如何实现可以捕获外部变量以及可以在其他时机进行调用的?

大致原理是:系统先创建了一个block相关的结构体,将当前作用域下的变量(个人觉得只有局部变量需要传递)和block块的函数地址传递给这个结构体存下来,这样当block代码块要执行的时候,拿着结构体里存的信息就可以执行。
具体实现代码可以看这里:ios - block原理解读(一)

上一篇 下一篇

猜你喜欢

热点阅读