美文网首页
iOS中的block

iOS中的block

作者: 炒河粉儿 | 来源:发表于2019-08-05 16:47 被阅读0次

block的定义

    typedef void (^YourBlock) (NSInteger);

    @property (nonatomic, copy) YourBlock yourBlock;

    self.yourBlock = ^(NSInteger a) {
        NSLog(@"%ld",(long)a);
    };
    
    _yourBlock(8);
    直接定义
    @property (nonatomic, copy) void(^myBlock)(NSInteger);
    self.myBlock = ^(NSInteger a) {
        NSLog(@"%ld",(long)a);
    };
    
    _myBlock(5);
    方法中定义
    void(^ourBlock)(NSInteger)  = ^(NSInteger a){
            NSLog(@"%ld",(long)a);
        };
    
    ourBlock(3);

在MRC下用copy修饰block,在MRC声明创建的block是在栈区,当函数之行结束的时候block就会被释放掉,所以需要用copy修饰block,将block拷贝一份到堆区,引用计数加1,,则block不会被释放。在ARC下,使用copy和strong修饰都可以,因为在ARC下声明创建block是在堆区的。

block的使用

block作为返回值,链式编程的思想。

self.select.where(@"哈哈");

- (ViewController *)select {
    return self;
}

- (void(^)(NSString *))where {
    void (^block)(NSString *) = ^(NSString *str){
        NSLog(@"%@",str);
    };
    
    return block;
}

block作为参数,函数式编程的思想。

typedef void (^NetBlock) (NSString *);

- (void)request:(NetBlock)netBlock {
    netBlock(@"网络请求结果");
}

[self request:^(NSString *result) {
        NSLog(@"%@",result);
    }];
    

block的底层

在block代码块中修改外部变量,需要用__block修饰外部变量。

    __block int c = 10;
    void(^Block)(NSInteger)  = ^(NSInteger a){
        a++;
        NSLog(@"%ld",(long)a);
    };
    
    Block(c);

int c是存储在栈区的。将c传入到block中,底层block执行时,会重新定义一个c,这个c是一个值,bound by copy,block代码块中使用的c其实是将新定义的c,实际上执行block代码块c累加操作的是新定义的c。所以在代码块中c++并不会改变一开始定义在栈区的c的值。当使用__block修饰c的时候,byref引用栈区的值进行copy到堆区,此时block代码块中进行c ++中的c实际上是传入了c的指针地址,此时修改这个值的时候,会达到值同步变化的情况。

block的循环引用

自动释放池释放对象,需要引用计数为0,才可以调起dealloc方法进行销毁,当A持有B,B也持有A的时候,互相强引用持有则不会使引用计数减1,因此造成循环引用,无法释放。

使用__weak修饰,在block代码块中使用__strong修饰。在block代码块中__strong有时候可以不用写。直接调用,此时self还没有进行释放的话就没有问题。如果是延时调用的话,比如block块中的代码为10秒后调用,如果在10秒前退出了当前控制器,则当前控制器会被释放销毁,则block中的代码块就不会执行了。__strong修饰后会使引用计数再次加1,此时控制器就不会被释放,当block的代码块里面执行完毕后,引用计数才会减1,此时会调用dealloc方法,控制器才会被释放。

    __weak typeof(self) weakSelf = self;
    self.lwnBlock = ^{
         __strong typeof(weakSelf) strongSelf = weakSelf;
        [strongSelf select];
        NSLog(@"你好");
    };

强弱共舞也可以解决循环引用

#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

强弱共舞的使用

 @weakify(self);
    
    bgViw.clickBlock = ^(id boj) {
    
        @strongify(self);
        [self hideClick:boj];
    };

使用__block解决循环引用,使用__block修饰,相当于重新copy 了一份self,使用这个拷贝出来的对象进行一系列的操作,但当代码块内容执行结束后,要在最后释放这个拷贝出来的对象,即bWeakSelf = nil,释放掉拷贝出来的self。

__block ViewController *bWeakSelf = self;
    self.lwnBlock = ^{
        NSLog(@"%@",bWeakSelf);
        bWeakSelf = nil;
    };

把self作为block中的参数传入也可以解决循环引用。声明一个block,参数为当前self类,调用时传入self。

typedef void (^LwnBlock2) (ViewController *);

@property (nonatomic, copy) LwnBlock2 lwnBlock2;

self.lwnBlock2 = ^(ViewController *obj) {
        NSLog(@"%@",obj);
    };
    self.lwnBlock2(self);

相关文章

网友评论

      本文标题:iOS中的block

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