美文网首页
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