block

作者: iLeooooo | 来源:发表于2019-03-07 17:42 被阅读0次

    O、题:block的原理是怎样?本质是什么?

    答:封装了函数调用以及调用环境的OC对象


    O.a、题:__block的作用是什么?有什么使用注意点?

    答:__block会将修饰的变量包装成一个__Block_byref_xxx对象,使用的时候要注意内存管理。


    O.b、题:block的属性修饰词为什么是copy?使用block有哪些使用注意?

    答:1. block一旦没有进行copy操作,就不会在堆上。 2. 使用注意:循环引用问题


    O.c、题:block在修改NSMutableArray,需不需要添加__block?

    答:不需要


    block的本质是什么:
    1. block本质上也是一个OC对象,它内部也有个isa指针。
    2. block是封装了函数调用以及函数调用环境的OC对象
    3. block的底层结构图如下:
    block
    block的类型:

    block有三种类型,可以通过调用class方法或者isa指针查看具体类型,最终都是继承NSBlock类型。

    继承关系:

    __NSGlobalBlock__ : __NSGlobalBlock : NSBlock : NSObject
    
    1. __NSGlobalBlock__(NSConcreteGlobalBlock)
    2. __NSStackBlock__(NSConcreteStackBlock)
    3. __NSMallocBlock__(NSConcreteMallocBlock)
    三种类型的block在内存中的布局:
    block布局位置
    三种类型的block的区别:
    block的区别
    每种类型的block调用copy后的结果:
    copy
    全局变量:数据段
    局部变量:栈段
    对象:堆段
    class对象:数据段
    
    在ARC环境下,编译器会根据情况自动将栈上的block复制到堆上,比如一下情况:
    1. block作为函数返回值。
    2. 将block赋值给__strong指针。
    3. block作为Cocoa API中方法名含义usingBlock的方法参数
    4. block作为GCD API的方法参数
    // 3
    [array enumerateObjectsUsingBlock:^(id  _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
    }];
    // 4
    dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(1.0 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
     });
    
    在MRC环境下,blcok属性建议的写法:
    @property (nonatomic, copy) void (^block) void;
    
    在ARC环境下,blcok属性建议的写法:
    @property (nonatomic, copy) void (^block) void;
    @property (nonatomic, strong) void (^block) void;
    
    当block内部访问了对象类型的auto变量
    1. 如果block是在栈上,将不会对auto变量产生强引用
    2. 如果block被拷贝到堆上
      • 会调用block内部的copy函数
      • copy函数内部会调用_Block_object_assign函数
      • _Block_object_assign函数会根据auto变量的修饰符(__strong,__weak, __unsafe unretained)做出相应的操作,类似于retain(形成强引用,弱引用)
    3. 如果block从堆上移除
    • 会调用block内部dispose函数
    • dispose函数内部会调用_Block_object_dispose函数
    • _Block_object_dispose函数会自动释放引用的auto变量,类似于release
    block
    __block修饰符
    1. __block可以用于解决block内部无法修改auto变量值的问题
    2. __block不能用来修饰全局变量、静态变量(static)
    3. 编译器会将__block修饰的变量包装成一个对象
    __block修饰符的内存管理
    1. 当block在栈上面的时候,并不会对__block变量产生强引用
    2. 当block被copy到堆上面时:
      • 会调用block内部的copy函数
      • copy函数内部会调用_Block_object_assign函数
      • _Block_object_assign函数会对__block变量产生强引用(retain)
    3. 当block从堆上移除时:
      • 会调用block内部dispose函数
      • dispose函数内部会调用_Block_object_dispose函数
      • _Block_object_dispose函数会自动释放__block变量产生(release)
    内存管理(持有)
    内存管理(释放)
    对象类型的auto变量,__block变量
    1. 当block在栈上的时候,都不会对他们产生强引用
    2. 当block拷贝到堆上的时候,都会通过copy函数来处理他们
      • __block变量(假设变量名为a)
      _Block_object_assign((void*)&dst->a, (void*)src->a, 8/*BLOCK_FIELD_IS_BYREF*/);
      
      • 对象类型的auto变量(假设变量名叫做p)
      _Block_object_assign((void*)&dst->p, (void*)src->p, 3/*BLOCK_FIELD_IS_OBJECT*/);
      
    3. 当block从堆上移除时,都会通过dispose函数来释放它们
      • __block变量(假设变量名叫做a)
      _Block_object_dispose((void*)src->a, 8/*BLOCK_FIELD_IS_BYREF*/);
      
      • 对象类型的auto变量(假设变量名叫做p)
      _Block_object_dispose((void*)src->p, 3/*BLOCK_FIELD_IS_OBJECT*/);
      

    内存管理
    __block修饰的对象类型
    1. 当__block变量在栈上时,不会对指向的对象产生强引用

    2. 当__block变量被copy到堆时

      • 会调用__block变量内部的copy函数
      • copy函数内部会调用_Block_object_assign函数
      • _Block_object_assign函数会根据所指向对象的修饰符(__strong、__weak、__unsafe_unretained)做出相应的操作,形成强引用(retain)或者弱引用(注意:这里仅限于ARC时会retain,MRC时不会retain)
    3. 如果__block变量从堆上移除

      • 会调用__block变量内部的dispose函数
      • dispose函数内部会调用_Block_object_dispose函数
      • _Block_object_dispose函数会自动释放指向的对象(release)
    循环引用
    循环引用
    1. 解决循环引用问题(ARC)
      • 用__weak、__unsafe_unretained解决
      • 用__block解决(必须要调用block)


    __weak : 不会产生强引用,指向的对象销毁时,会自动让指针置为nil。
    __unsafe_unretained : 不会产生强引用,不安全,指向的对象销毁时,指针存储的地址值不变。
    
    1. 解决循环引用问题(MRC)
      • 用__unsafe_unretained解决
      • 用__block解决


    相关文章

      网友评论

        本文标题:block

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