iOS - block

一、简述
block 分类: NSGlobalBlockNSMallocBlockNSstackBlock,通过内存的分部部局来分类。
block就是保存一段代码块,想用的时候随时调用。
block 特性:自动捕获变量

因为ARC下,系统会自动的对block进行copy操作,所以在MRC下测试
MRC下测试代码

    //NSGlobalBlock 全局静态block,没访问外部局部变量,没copy
    void(^globalBlock1)(void)= ^{
        NSLog(@"TestBlock");
    };
    NSLog(@"globalBlock1 = %@",globalBlock1);

    //NSGlobalBlock 全局静态block,没访问外部变量
    void(^globalBlock2)(void) = [^{
        NSLog(@"TestBlock");
    } copy];
    NSLog(@"globalBlock2 = %@",globalBlock2);
///
输出
globalBlock1 = <__NSGlobalBlock__: 0x100c060c0>
globalBlock2 = <__NSGlobalBlock__: 0x100c060e0>

////////////////////////////////////////////////////////////////////////////////////////
    int a = 10;
    //NSStackBlock ,引用外部变量,没有copy,保存在栈中的block,出函数作用销毁
    void(^stackBlock)(void) = ^{
        NSLog(@"TestBlock %d",a);
    };
    NSLog(@"stackBlock = %@",stackBlock);
///
输出
stackBlock = <__NSStackBlock__: 0x16f6974e8>
////////////////////////////////////////////////////////////////////////////////////////

    //NSMallocBlock 引用外部变量,copy之后,保存在堆中的block,当引用计数为0时被销毁。
    void(^mallocBlock)(void)  = [^{
        NSLog(@"TestBlock %d",a);
    } copy];
    
    NSLog(@"mallocBlock = %@",mallocBlock);
///输出
mallocBlock = <__NSMallocBlock__: 0x11f163200>

那ARC下是不是就只有NSMallocBlockNSGlobalBlock,没有NSstackBlock了呢,也不是。
ARC下NSstackBlock测试代码

    int a = 10;
    
    __weak void(^weakBlock)(void) = ^{
        NSLog(@"weakBlock a = %d",a);
    };
    NSLog(@"weakBlock%@",weakBlock);
///输出
weakBlock<__NSStackBlock__: 0x16bbf74f8>

二、block的简单使用

//1、作为对象属性
typedef void(^ Myblock)(void);
@property(nonatomic,strong) Myblock block;
//或
@property(nonatomic,strong) void(^block)(void);

//2、作为方法参数
- (void)btnHandler:(void(^)(void))block
{
    block();
}

//3、作为方法返回值。点语法调用、响应式编程
- (void(^)(int))run{
    
    return ^(int m){
        NSLog(@"跑起来,跑了%d米",m);
    };
}
p.run(3);

三、循环引用解决方式

    //方法1
    //只加__weak,在VC被释放后,操作有可能无法完成,在内部加上strong后,可保证操作完成,strongSelf是局部变量,在操作完成出了block作用域后,会被释放,不会引起循环引用
    __weak typeof(self) weakSelf = self;
    self.block = ^{
        __strong typeof(self) strongSelf = weakSelf;
        NSLog(@"%@", strongSelf.title);
    };
    //方法2
    //把self放到局部变量中,self -> block -> vc -> self,在使用完成之后,vc = nil;即可打破循环引用,加__block是为了让vc能在block中被修改。
    __block ViewController * vc = self
    self.block = ^{
        NSLog(@"%@", vc.title);
        vc = nil;
    };
    //方法3
    //传参,参数在操作执行完成,出了block作用域之后,会被释放,打破循环引用。
    @property (nonatomic, copy) void(^block)(ViewController * vc);
    self.block = ^(ViewController * vc){
            NSLog(@"%@",vc.name);
    };
    self.block(self);

四、为什么要给int a加__block,加不加__block有什么区别
1、不加__block,变量a被捕获,为值传递,只读,只可NSLog输出,如果在block内修改a的话,编译器报错。
2、加__block后,是指针传递,可读可写,可对a的值进行修改。

    __block int a = 10;
    void(^block)(void) = ^{
        a++;
    };
    block();

五、block为什么用copy关键字修饰
在MRC下,引入外部变量的block被存放在栈区,出了作用域会被释放,再次调用会造成崩溃。使用copy可以把block拷贝到堆区中,只要对象不销毁,就可以一直调用。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容