OC:深入探究 block

主要分析了block在持有__block呜魄、__weak、__strong修飾的對(duì)象時(shí)步绸,block結(jié)構(gòu)發(fā)生的變化尝丐。

以及block對(duì)持有變量的引用計(jì)數(shù)造成的具體影響显拜。

思考:

@implementation TestCode
- (void)testFunc {
    @weakify(self)
    self.block111 = ^{
        @strongify(self);
        dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2.0 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
            if (self) {
                printf("\n\nstrongPerson1 Retain Count = %ld",CFGetRetainCount((__bridge CFTypeRef)(self)));
            }else{
                printf("self Retain Count = 0 \n");
            }
        });
    };
}

- (void)dealloc {
    printf("\n");
    printf("? 【dealloc】 Retain Count = 0");
}
@end

  
@implementation ViewController
- (void)viewDidLoad {
    [super viewDidLoad];
    TestCode *t = [[TestCode alloc]init];
    [t testFunc];
    
    if (t.block111) {
        t.block111();
    }
}
@end

注意: 以下block111是self所持有的block

  • 如果在block111 中對(duì) NSMutableArray *arrayM 進(jìn)行增刪元素, arrayM是否需要用__block修飾?

  • block111 中對(duì)weakSelf進(jìn)行 __strong typeof(weakSelf) strongSelf = weakSelf 修飾

    • 如果block一直不調(diào)用爹袁,那么self是否可以正常銷毀远荠?
    • 當(dāng)運(yùn)行到__strong typeof(weakSelf) strongSelf = weakSelf的下一行時(shí),self引用計(jì)數(shù)最少是多少失息?

一:基本介紹

定義

Block 是帶有自動(dòng)變量(局部變量)的匿名函數(shù)譬淳, 是 C 語言的擴(kuò)充功能,其本質(zhì)是一個(gè)OC對(duì)象盹兢。

  1. 作為屬性

    @property (nonatomic,copy) void(^block)(void);

  2. 作為參數(shù)

    - (void) getDataWithBlock:(id(^)(id parameter))block;

  3. 作為返回值(masonry)

    - (MASConstraint * (^)(id))equalTo

結(jié)構(gòu)

- (void)testFunc {
    self.block111 = ^{
        printf("block測試代碼");
    };
    self.block111();
}

OC代碼轉(zhuǎn)成c++代碼

clang -x objective-c -rewrite-objc -isysroot /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator.sdk -fobjc-arc -fobjc-runtime=macosx-10.13 xxxxxx.m

static void _I_TestCode_testFunc(TestCode * self, SEL _cmd) {
    /// self.block = &__TestCode__testFunc_block_impl_0(A,B)
    ((void (*)(id, SEL, void (^ _Nonnull)()))(void *)objc_msgSend)
     ((id)self, sel_registerName("setBlock111:"),
      (
       (void (*)())&__TestCode__testFunc_block_impl_0
        (
         (void *)__TestCode__testFunc_block_func_0,// 參數(shù)1
         &__TestCode__testFunc_block_desc_0_DATA// 參數(shù)2__TestCode__testFunc_block_desc_0,
        )
       )
     );
    
    ((void (*(*)(id, SEL))())(void *)objc_msgSend)((id)self, sel_registerName("block111"))();
}

上段代碼的基本意思是

  1. self.block = &__TestCode__testFunc_block_impl_0(A,B)

    1. A: __TestCode__testFunc_block_func_0
    2. B: __TestCode__testFunc_block_desc_0_DATA

1. __TestCode__testFunc_block_impl_0

struct __TestCode__testFunc_block_impl_0 {
  
  struct __block_impl impl;
  struct __TestCode__testFunc_block_desc_0* Desc;
  
  __TestCode__testFunc_block_impl_0(void *fp, struct __TestCode__testFunc_block_desc_0 *desc, int flags=0) {
    impl.isa = &_NSConcreteStackBlock;
    impl.Flags = flags;
    impl.FuncPtr = fp;
    Desc = desc;
  }
};

命名規(guī)律:_類名_方法名_block_impl_層級(jí)

上述代碼中可以看出block 被編譯成了__TestCode__testFunc_block_impl_0結(jié)構(gòu)體

  1. 其內(nèi)部有一個(gè)同名的構(gòu)造函數(shù)__TestCode__testFunc_block_impl_0
  2. 兩個(gè)屬性
    1. __block_impl impl

    2. __TestCode__testFunc_block_desc_0* Desc

2. __block_impl

struct __block_impl {
  void *isa;// 指向了&_NSConcreteStackBlock
  int Flags;
  int Reserved;
  void *FuncPtr; // 用于方法的儲(chǔ)存本質(zhì)是一個(gè) __TestCode__testFunc_block_func_0 c函數(shù)
};

可以發(fā)現(xiàn)__block_impl結(jié)構(gòu)體內(nèi)部就有一個(gè)isa指針邻梆。因此可以證明block本質(zhì)上就是一個(gè)oc對(duì)象。

__block_impl結(jié)構(gòu)體中isa指針存儲(chǔ)著&_NSConcreteStackBlock地址绎秒,可以暫時(shí)理解為其類對(duì)象地址浦妄,block就是_NSConcreteStackBlock類型的。

  1. 看到isa就會(huì)聯(lián)想到之前在objc_class結(jié)構(gòu)體见芹,因此我們的block本質(zhì)上也是一個(gè)對(duì)象【而且是個(gè)類對(duì)象】
    我們知道實(shí)例對(duì)象->類對(duì)象->元類構(gòu)成了isa鏈中的一條剂娄,而這個(gè)__block_impl結(jié)構(gòu)體占據(jù)的是中間類對(duì)象的位置
  2. 這里的isa指針會(huì)指向元類,這里的元類主要是為了說明這個(gè)塊的存儲(chǔ)區(qū)域

__TestCode__testFunc_block_func_0

static void __TestCode__testFunc_block_func_0(struct __TestCode__testFunc_block_impl_0 *__cself) {
        printf("block測試代碼");
}

__TestCode__testFunc_block_func_0 中存放的是block中的代碼

3. __TestCode__testFunc_block_desc_0

static struct __TestCode__testFunc_block_desc_0 {
  size_t reserved;
  size_t Block_size;
} __TestCode__testFunc_block_desc_0_DATA = { 0, sizeof(struct __TestCode__testFunc_block_impl_0)};

主要是存儲(chǔ)了block的大小

4. 同名的構(gòu)造函數(shù)__TestCode__testFunc_block_impl_0(void *fp, struct __TestCode__testFunc_block_desc_0 *desc, int flags=0)

__TestCode__testFunc_block_impl_0
    (void *fp, struct __TestCode__testFunc_block_desc_0 *desc, int flags=0)
    {
        impl.isa = &_NSConcreteStackBlock;
        impl.Flags = flags;
        impl.FuncPtr = fp;
        Desc = desc;
    }

同名函數(shù)主要對(duì)兩個(gè)屬性進(jìn)行了賦值

  • void *fp 就是 (void *)__TestCode__testFunc_block_func_0__
  • __ struct __TestCode__testFunc_block_desc_0 *desc 就是 &__TestCode__testFunc_block_desc_0_DATA

5. 結(jié)構(gòu)圖

image

二:持有變量時(shí)block的結(jié)構(gòu)

以上分析的是 block 不持有任何外部變量玄呛,但是當(dāng)block持有外部變量的時(shí)候宜咒,就會(huì)額外生成一些東西。

持有基本數(shù)據(jù)類型

持有的基本數(shù)據(jù)類型分為是否用__block修飾把鉴,如下,a__block修飾儿咱,b沒有庭砍。

- (void)testFunc {
    __block NSInteger a = 0;
    NSInteger b = 0;
    self.block111 = ^{
        a = 12 + b;
        printf("block測試代碼");
    };
    self.block111();
}

思考

a__block修飾后可以修改,必然a從值傳遞混埠,變成了地址傳遞怠缸。

  1. __bloka封裝成了什么結(jié)構(gòu)?
  2. 結(jié)構(gòu)a的值到底存在哪里钳宪?
  3. 結(jié)構(gòu)a是怎么管理內(nèi)存的揭北?

要回答上述問題扳炬,我們需要查看- (void)testFunc{}編譯的源碼:

編譯后:

static void _I_TestCode_testFunc(TestCode * self, SEL _cmd) {
    // 結(jié)構(gòu)體 a 的生成  (__block NSInteger a = 0;)
    __attribute__((__blocks__(byref))) __Block_byref_a_0 a =
    {
        (void*)0, // isa
        (__Block_byref_a_0 *)&a,// a地址的傳遞
        0,// flags
        sizeof(__Block_byref_a_0),// size
        0// a的值
    };
    
    NSInteger b = 0;
    
    ((void (*)(id, SEL, void (^ _Nonnull)()))(void *)objc_msgSend)
    ((id)self, sel_registerName("setBlock111:"),
     
     /// 初始化__TestCode__testFunc_block_impl_0結(jié)構(gòu)體
     ((void (*)())&__TestCode__testFunc_block_impl_0
      (
       (void *)__TestCode__testFunc_block_func_0,
       &__TestCode__testFunc_block_desc_0_DATA,
       
       b,//值傳遞b
       (__Block_byref_a_0 *)&a,//把結(jié)構(gòu)體(對(duì)象)a的地址傳了進(jìn)去
       
       570425344
       ))
     );
    
    ((void (*(*)(id, SEL))())(void *)objc_msgSend)((id)self, sel_registerName("block111"))();
}

1. __Block_byref_a_0

struct __Block_byref_a_0 {
  void *__isa;
__Block_byref_a_0 *__forwarding;
 int __flags;
 int __size;
 NSInteger a;
};

// 結(jié)構(gòu)體 a 的生成 
    __attribute__((__blocks__(byref))) __Block_byref_a_0 a =
    {
        (void*)0, // isa
        (__Block_byref_a_0 *)&a,// a地址的傳遞
        0,// flags
        sizeof(__Block_byref_a_0),// size
        0// a的值
    };
  • 用了__block修飾的a,生成了一個(gè)用__attribute__ 修飾的 __Block_byref_a_0類型的結(jié)構(gòu)體搔体。
  • 結(jié)構(gòu)體內(nèi)部有一個(gè)isa指針,說明__Block_byref_a_0其本質(zhì)也是一個(gè)OC對(duì)象

2. __TestCode__testFunc_block_impl_0結(jié)構(gòu)體

struct __TestCode__testFunc_block_impl_0 {
    
  struct __block_impl impl;
  struct __TestCode__testFunc_block_desc_0* Desc;
    
  NSInteger b;
  __Block_byref_a_0 *a; // by ref
    
  // 同名的構(gòu)造函數(shù)
  __TestCode__testFunc_block_impl_0
    (
     
     void *fp,
     struct __TestCode__testFunc_block_desc_0 *desc,
     NSInteger _b,
     __Block_byref_a_0 *_a,
     int flags=0
     
     ) : b(_b), a(_a->__forwarding) { ... }
};

生成了新的屬性:

  • NSInteger b

    • _b就是棧區(qū)的b
    • b 值傳遞
  • __Block_byref_a_0 *a

    • 由于賦值到__TestCode__testFunc_block_impl_0時(shí)恨樟,傳遞的是 棧區(qū)的__Block_byref_a_0 a的地址,所以 _a == &a

    • 因?yàn)?code>_a->__forwarding就是&_a因此__TestCode__testFunc_block_impl_0結(jié)構(gòu)體中的a指向的就是棧中的a

小結(jié)論:

  1. block中的b和外部的b,只是值傳遞疚俱,因此即便外部修改了b的值劝术,也不會(huì)對(duì)blockb產(chǎn)生影響。
  2. __block a;a包裝成了一個(gè)結(jié)構(gòu)體,而block內(nèi)部屬性__Block_byref_a_0 *a就是棧區(qū)結(jié)構(gòu)體a的地址
  3. 此時(shí)呆奕, block沒有copy操作养晋,所以block存在棧區(qū),結(jié)構(gòu)體a也存在棧區(qū)

3. __TestCode__testFunc_block_desc_0


static struct __TestCode__testFunc_block_desc_0 {
  size_t reserved;
  size_t Block_size;
   //copy 函數(shù)
  void (*copy)(
    struct __TestCode__testFunc_block_impl_0*, 
    struct __TestCode__testFunc_block_impl_0*
  );
  // dispose 函數(shù)
  void (*dispose)(struct __TestCode__testFunc_block_impl_0*);
    
} __TestCode__testFunc_block_desc_0_DATA = 
                                                                    { 0,// reserved
                                   sizeof(struct __TestCode__testFunc_block_impl_0), //size
                                   __TestCode__testFunc_block_copy_0,//copy
                                   __TestCode__testFunc_block_dispose_0//dispose
                                   };

生成了 copy dispose 函數(shù)

a. __TestCode__testFunc_block_copy_0
  1. block被拷貝到堆區(qū)的時(shí)候調(diào)用

  2. 實(shí)現(xiàn)函數(shù)是 _Block_object_assign梁钾,它根據(jù)對(duì)象的 flags 來判斷是否需要拷貝绳泉,或者只是賦值。

// copy
static void __TestCode__testFunc_block_copy_0(struct __TestCode__testFunc_block_impl_0*dst, struct __TestCode__testFunc_block_impl_0*src){
  _Block_object_assign(
                        (void*)&dst->a, 
            (void*)src->a,
            8/*BLOCK_FIELD_IS_BYREF*/
                        );
}
_Block_object_assign

函數(shù)實(shí)現(xiàn)在 runtime.c

/**
_Block_object_assign參數(shù)flag相關(guān)
                // 是一個(gè)對(duì)象
        BLOCK_FIELD_IS_OBJECT   =  3, 
        // 是一個(gè)block
        BLOCK_FIELD_IS_BLOCK    =  7, 
        // 被__block修飾的變量
        BLOCK_FIELD_IS_BYREF    =  8,  
        // 被__weak修飾的變量姆泻,只能被輔助copy函數(shù)使用 
        BLOCK_FIELD_IS_WEAK     = 16,  
        // block輔助函數(shù)調(diào)用(告訴內(nèi)部實(shí)現(xiàn)不要進(jìn)行retain或者copy)
        BLOCK_BYREF_CALLER      = 128 
**/

void _Block_object_assign(void *destAddr, const void *object, const int flags) {
  
  // BLOCK_BYREF_CALLER block輔助函數(shù)調(diào)用(告訴內(nèi)部實(shí)現(xiàn)不要進(jìn)行retain或者copy)
    if ((flags & BLOCK_BYREF_CALLER) == BLOCK_BYREF_CALLER) {
      
      //BLOCK_FIELD_IS_WEAK 被__weak修飾的變量零酪,只能被輔助copy函數(shù)使用 
        if ((flags & BLOCK_FIELD_IS_WEAK) == BLOCK_FIELD_IS_WEAK) {
            _Block_assign_weak(object, destAddr);
        }
        else {
            _Block_assign((void *)object, destAddr);
        }
    }
  
  // 被__block修飾的變量
    else if ((flags & BLOCK_FIELD_IS_BYREF) == BLOCK_FIELD_IS_BYREF)  {
      ///最終走到這邊 
        _Block_byref_assign_copy(destAddr, object, flags);
    }
  
  // 是一個(gè)block
    else if ((flags & BLOCK_FIELD_IS_BLOCK) == BLOCK_FIELD_IS_BLOCK) {
        _Block_assign(_Block_copy_internal(object, flags), destAddr);
    }
  
  // 是一個(gè)對(duì)象
    else if ((flags & BLOCK_FIELD_IS_OBJECT) == BLOCK_FIELD_IS_OBJECT) {
        _Block_retain_object(object);
        _Block_assign((void *)object, destAddr);
    }
}
/*
Block_private.h
https://opensource.apple.com/source/libclosure/libclosure-73/Block_private.h
*/
 enum {
        BLOCK_DEALLOCATING =      (0x0001),  // runtime
        BLOCK_REFCOUNT_MASK =     (0xfffe),  // runtime
        BLOCK_NEEDS_FREE =        (1 << 24), // runtime
        BLOCK_HAS_COPY_DISPOSE =  (1 << 25), // compiler
        BLOCK_HAS_CTOR =          (1 << 26), // compiler: helpers have C++ code
        BLOCK_IS_GC =             (1 << 27), // runtime
        BLOCK_IS_GLOBAL =         (1 << 28), // compiler
        BLOCK_USE_STRET =         (1 << 29), // compiler: undefined if !BLOCK_HAS_SIGNATURE
        BLOCK_HAS_SIGNATURE  =    (1 << 30), // compiler
        BLOCK_HAS_EXTENDED_LAYOUT=(1 << 31)  // compiler
    };

struct Block_byref {
    void *isa;
    struct Block_byref *forwarding;
    int flags; /* refcount; */
    int size;
};


/** runtime.c
http://llvm.org/svn/llvm-project/compiler-rt/trunk/lib/BlocksRuntime/runtime.c
*/
static void *_Block_copy_class = _NSConcreteMallocBlock;
static void *_Block_copy_finalizing_class = _NSConcreteMallocBlock;
static int _Block_copy_flag = BLOCK_NEEDS_FREE;
static int _Byref_flag_initial_value = BLOCK_NEEDS_FREE | 2;

static void _Block_byref_assign_copy(void *dest, const void *arg, const int flags) {

    struct Block_byref **destp = (struct Block_byref **)dest;
    struct Block_byref *src = (struct Block_byref *)arg;

        //不需要做任何操作
    if (src->forwarding->flags & BLOCK_IS_GC) {
    }
  
        // 需要copy到堆區(qū) 并且需要操作引用計(jì)數(shù)
    else if ((src->forwarding->flags & BLOCK_REFCOUNT_MASK) == 0) {
        // src points to stack
        bool isWeak = ((flags & (BLOCK_FIELD_IS_BYREF|BLOCK_FIELD_IS_WEAK)) == (BLOCK_FIELD_IS_BYREF|BLOCK_FIELD_IS_WEAK));
        // if its weak ask for an object (only matters under GC)
        struct Block_byref *copy = (struct Block_byref *)_Block_allocator(src->size, false, isWeak);
        copy->flags = src->flags | _Byref_flag_initial_value; // non-GC one for caller, one for stack
        copy->forwarding = copy; // patch heap copy to point to itself (skip write-barrier)
        src->forwarding = copy;  // patch stack to point to heap copy
        copy->size = src->size;
        if (isWeak) {
            copy->isa = &_NSConcreteWeakBlockVariable;  // mark isa field so it gets weak scanning
        }
        if (src->flags & BLOCK_HAS_COPY_DISPOSE) {
            // Trust copy helper to copy everything of interest
            // If more than one field shows up in a byref block this is wrong XXX
            copy->byref_keep = src->byref_keep;
            copy->byref_destroy = src->byref_destroy;
            (*src->byref_keep)(copy, src);
        }
        else {
            // just bits.  Blast 'em using _Block_memmove in case they're __strong
            _Block_memmove(
                (void *)&copy->byref_keep,
                (void *)&src->byref_keep,
                src->size - sizeof(struct Block_byref_header));
        }
    }
    // 已經(jīng)復(fù)制到堆、只操作引用計(jì)數(shù)
    else if ((src->forwarding->flags & BLOCK_NEEDS_FREE) == BLOCK_NEEDS_FREE) {
        latching_incr_int(&src->forwarding->flags);
    }
    // assign byref data block pointer into new Block
    // 其實(shí)進(jìn)行了 *destp = src->forwarding 操作麦射,把棧區(qū)的a蛾娶,變成了 Block_byref *copy
    _Block_assign(src->forwarding, (void **)destp);
}

static void (*_Block_assign)(void *value, void **destptr) = _Block_assign_default;

static void _Block_assign_default(void *value, void **destptr) {
    *destptr = value;
}

省略后的代碼


struct Block_byref {
    void *isa;
    struct Block_byref *forwarding;
    int flags; /* refcount; */
    int size;
};

static void _Block_byref_assign_copy(void *dest, const void *arg, const int flags) {
    ...
    struct Block_byref *copy = (struct Block_byref *)_Block_allocator(src->size, false, isWeak);
    copy->flags = src->flags | _Byref_flag_initial_value; // non-GC one for caller, one for stack
    // 堆中拷貝的forwarding指向它自己
    copy->forwarding = copy; // patch heap copy to point to itself (skip write-barrier)
    // 棧中的forwarding指向堆中的新對(duì)象
    src->forwarding = copy;  // patch stack to point to heap copy
    copy->size = src->size;
    ...
     // 其實(shí)進(jìn)行了 *destp = src->forwarding 操作,把棧區(qū)的a潜秋,變成了 Block_byref *copy
    _Block_assign(src->forwarding, (void **)destp);
}

可以看到蛔琅,Block_byref__Block_byref_a_0 的前4個(gè)成員類型相同,可以互相轉(zhuǎn)化峻呛。

b. __TestCode__testFunc_block_dispose_0
// dispose
static void __TestCode__testFunc_block_dispose_0(struct __TestCode__testFunc_block_impl_0*src){
_Block_object_dispose((void*)src->a, 8/*BLOCK_FIELD_IS_BYREF*/);
}
_Block_object_dispose
void _Block_object_dispose(const void *object, const int flags) {
    //printf("_Block_object_dispose(%p, %x)\n", object, flags);
    if (flags & BLOCK_FIELD_IS_BYREF)  {
      // 釋放 __block 修飾的變量
        _Block_byref_release(object);
    }
    else if ((flags & (BLOCK_FIELD_IS_BLOCK|BLOCK_BYREF_CALLER)) == BLOCK_FIELD_IS_BLOCK) {
                // 釋放block 引用的 block
        _Block_destroy(object);
    }
    else if ((flags & (BLOCK_FIELD_IS_WEAK|BLOCK_FIELD_IS_BLOCK|BLOCK_BYREF_CALLER)) == BLOCK_FIELD_IS_OBJECT) {
        // 釋放block 引用的對(duì)象
        _Block_release_object(object);
    }
}
static void _Block_byref_release(const void *arg) {
    struct Block_byref *shared_struct = (struct Block_byref *)arg;
    int refcount;

    shared_struct = shared_struct->forwarding;

    if ((shared_struct->flags & BLOCK_NEEDS_FREE) == 0) {
        return; // stack or GC or global
    }
    refcount = shared_struct->flags & BLOCK_REFCOUNT_MASK;
    if (refcount <= 0) {
        printf("_Block_byref_release: Block byref data structure at %p underflowed\n", arg);
    }
    else if ((latching_decr_int(&shared_struct->flags) & BLOCK_REFCOUNT_MASK) == 0) {
        if (shared_struct->flags & BLOCK_HAS_COPY_DISPOSE) {
            (*shared_struct->byref_destroy)(shared_struct);
        }
        _Block_deallocator((struct Block_layout *)shared_struct);
    }
}

static void (*_Block_deallocator)(const void *) = (void (*)(const void *))free;

static int latching_decr_int(int *where) {
    while (1) {
        int old_value = *(volatile int *)where;
        if ((old_value & BLOCK_REFCOUNT_MASK) == BLOCK_REFCOUNT_MASK) {
            return BLOCK_REFCOUNT_MASK;
        }
        if ((old_value & BLOCK_REFCOUNT_MASK) == 0) {
            return 0;
        }
        if (OSAtomicCompareAndSwapInt(old_value, old_value-1, (volatile int *)where)) {
            return old_value-1;
        }
    }
}

__block修飾的變量罗售,釋放時(shí)要用 latching_decr_int函數(shù)減引用計(jì)數(shù),直到計(jì)數(shù)為0钩述,就釋放該對(duì)象寨躁;

而普通的對(duì)象、block牙勘,就直接釋放銷毀职恳。

小結(jié):

  1. 生成了copy despose函數(shù)。

  2. copy 調(diào)用時(shí)機(jī):

    1. 當(dāng)block進(jìn)行copy操作的時(shí)候就會(huì)自動(dòng)調(diào)用__TestCode__testFunc_block_desc_0內(nèi)部的__TestCode__testFunc_block_copy_0函數(shù)方面,__TestCode__testFunc_block_copy_0函數(shù)內(nèi)部會(huì)調(diào)用_Block_object_assign函數(shù)放钦。
    2. _Block_object_assign內(nèi)部是根據(jù)傳遞的flags類型來對(duì)a進(jìn)行copyretain操作
  3. despose 調(diào)用時(shí)機(jī):

    1. 當(dāng)block從堆中移除時(shí)就會(huì)自動(dòng)調(diào)用__TestCode__testFunc_block_desc_0__TestCode__testFunc_block_dispose_0函數(shù)恭金,__TestCode__testFunc_block_dispose_0函數(shù)內(nèi)部會(huì)調(diào)用_Block_object_dispose函數(shù)操禀。
    2. _Block_object_dispose會(huì)對(duì) a做釋放操作,類似于release横腿。

4. __TestCode__testFunc_block_func_0

__TestCode__testFunc_block_func_0__block_impl結(jié)構(gòu)體中存儲(chǔ)的block代碼

static void __TestCode__testFunc_block_func_0(struct __TestCode__testFunc_block_impl_0 *__cself) {
  
  __Block_byref_a_0 *a = __cself->a; // bound by ref
  NSInteger b = __cself->b; // bound by copy
  
  (a->__forwarding->a) = 12 + b;
   printf("block測試代碼");
}

__cself就是我們定義的block

a->__forwarding其實(shí)修改的就是我們堆區(qū)的(Block_byref) copy (注意 在ARC下我們的block會(huì)自動(dòng)copy)

下圖在TestCode.m中自定義了結(jié)構(gòu)體:

struct __Block_byref_a_0 {
    void *__isa;
    struct __Block_byref_a_0 *__forwarding;
    int __flags;
    int __size;
    NSInteger a;
};
struct __block_impl {
    void *isa;// 指向了&_NSConcreteStackBlock
    int Flags;
    int Reserved;
    void *FuncPtr; // 用于方法的儲(chǔ)存本質(zhì)是一個(gè) __TestCode__testFunc_block_func_0 c函數(shù)
};
struct __TestCode__testFunc_block_impl_0 {
    
    struct __block_impl impl;
    struct __TestCode__testFunc_block_desc_0* Desc;
    struct __Block_byref_a_0 *a; // by ref
};
截屏2020-02-01下午4.30.11.png

5. 結(jié)構(gòu)圖

__block NSInteger a = 0;
NSInteger b = 0;
self.block111 = ^{
    a = 12 + b;
    printf("block測試代碼");
};
image

持有對(duì)象類型

對(duì)象類型的引用分為三種情況:

  1. __block 修飾
  2. __strong 修飾(@strongify)
  3. __weak 修飾 (@weakify)

??注意下面的代碼產(chǎn)生了循環(huán)引用颓屑,隨后會(huì)做詳細(xì)的分析

- (void)testFunc {
    
    __weak typeof(self)weakSelf = self;
    __block TestCode *blockSelf = weakSelf;
    
    self.block111 = ^{
        __strong typeof(weakSelf)strongSelf = weakSelf;
        void(^block222)(void) = ^{
            blockSelf = strongSelf;
            printf("\nblock測試代碼\n");
        };
        block222();
    };
    
    self.block111();
}

編譯上述代碼:

static void _I_TestCode_testFunc(TestCode * self, SEL _cmd) {

    __attribute__((objc_ownership(weak))) typeof(self)weakSelf = self;
    __attribute__((__blocks__(byref))) __Block_byref_blockSelf_0 blockSelf =
    {
        (void*)0,
        (__Block_byref_blockSelf_0 *)&blockSelf,
        33554432,
        sizeof(__Block_byref_blockSelf_0),
        __Block_byref_id_object_copy_131,
        __Block_byref_id_object_dispose_131,
        weakSelf
    };

    // 創(chuàng)建 __TestCode__testFunc_block_impl_1
    ((void (*)(id, SEL, void (^ _Nonnull)()))(void *)objc_msgSend)((id)self, sel_registerName("setBlock111:"), ((void (*)())&__TestCode__testFunc_block_impl_1
     (//參數(shù):
      (void *)__TestCode__testFunc_block_func_1,
      &__TestCode__testFunc_block_desc_1_DATA,
      weakSelf,
      (__Block_byref_blockSelf_0 *)&blockSelf,
      570425344)
      ));

    ((void (*(*)(id, SEL))())(void *)objc_msgSend)((id)self, sel_registerName("block111"))();
}

1. __Block_byref_blockSelf_0

struct __Block_byref_blockSelf_0 {
  //【值為:0】[8個(gè)字節(jié)]
  void *__isa;
  //【值為&blockSelf】,[8個(gè)字節(jié)]
__Block_byref_blockSelf_0 *__forwarding;
  
 int __flags;//【值為33554432】,[4個(gè)字節(jié)]
 int __size;//【值為sizeof(__Block_byref_blockSelf_0)】,[4個(gè)字節(jié)]
  
  //【__Block_byref_id_object_copy_131】[8個(gè)字節(jié)]
 void (*__Block_byref_id_object_copy)(void*, void*);
  //【__Block_byref_id_object_dispose_131】,[8個(gè)字節(jié)]
 void (*__Block_byref_id_object_dispose)(void*);
  
 TestCode *__strong blockSelf;//【weakSelf】[8個(gè)字節(jié)]
};
/// 共48個(gè)字節(jié)

self使用__block修飾后斤寂,blockPerson 被包裝成了一個(gè)與__Block_byref_a_0相似的結(jié)構(gòu)體

只是比__Block_byref_a_0多了兩個(gè)函數(shù):

  1. __Block_byref_id_object_copy值為__Block_byref_id_object_copy_131
  2. __Block_byref_id_object_dispose值為__Block_byref_id_object_dispose_131

??值得注意的是blockSelf用了__strong修飾,因此產(chǎn)生了循環(huán)引用揪惦!需要改成__block typeof(weakSelf)blockSelf = weakSelf; 下面會(huì)有詳細(xì)解釋

__Block_byref_id_object_copy_131 與 __Block_byref_id_object_dispose_131

static void __Block_byref_id_object_copy_131(void *dst, void *src) {
 _Block_object_assign((char*)dst + 40, *(void * ) ((char)src + 40), 131);
}
static void __Block_byref_id_object_dispose_131(void *src) {
 _Block_object_dispose(*(void * *) ((char*)src + 40), 131);
}

內(nèi)部調(diào)用函數(shù)為_Block_object_assign

dstsrc就是blockSelf__Block_byref_blockSelf_0結(jié)構(gòu)體指針

__Block_byref_blockSelf_0共48個(gè)字節(jié)遍搞,所以(char*)dst + 40(char)src + 40,找到的就是TestCode *__strong blockSelf

最后的flags傳遞的是131 = 3|128 即 : BLOCK_FIELD_IS_OBJECT|BLOCK_FIELD_IS_CALLER

調(diào)用時(shí)機(jī):block執(zhí)行copy操作丹擎,后面會(huì)詳細(xì)分析尾抑。

2. __TestCode__testFunc_block_impl_1

struct __TestCode__testFunc_block_impl_1 {
  struct __block_impl impl;
  struct __TestCode__testFunc_block_desc_1* Desc;
    
  TestCode *const __weak weakSelf;
  __Block_byref_blockSelf_0 *blockSelf; // by ref
    
  __TestCode__testFunc_block_impl_1(
                                    void *fp,
                                    struct __TestCode__testFunc_block_desc_1 *desc,
                                    TestCode *const __weak _weakSelf,
                                    __Block_byref_blockSelf_0 *_blockSelf,
                                    int flags=0
                                    ) : weakSelf(_weakSelf), blockSelf(_blockSelf->__forwarding) {
    impl.isa = &_NSConcreteStackBlock;
    impl.Flags = flags;
    impl.FuncPtr = fp;
    Desc = desc;
  }
};

生成了兩個(gè)成員變量:Person *__weak weakPerson;__Block_byref_blockPerson_0 *blockPerson;

**a. __block_impl impl **

結(jié)構(gòu)沒有任何變化

  1. flags: 570425344表示BLOCK_HAS_COPY_DISPOSE | BLOCK_HAS_DESCRIPTOR蒂培,即(1<<25 | 1<<29)
  2. FuncPtr: __TestCode__testFunc_block_func_1

3. __TestCode__testFunc_block_desc_1

結(jié)構(gòu)沒有任何變化

desc:結(jié)構(gòu)體__TestCode__testFunc_block_desc_1_DATA

static struct __TestCode__testFunc_block_desc_1 {
  size_t reserved;
  size_t Block_size;
  void (*copy)(struct __TestCode__testFunc_block_impl_1*, struct __TestCode__testFunc_block_impl_1*);
  void (*dispose)(struct __TestCode__testFunc_block_impl_1*);
} __TestCode__testFunc_block_desc_1_DATA = {
    0,
    sizeof(struct __TestCode__testFunc_block_impl_1),
    __TestCode__testFunc_block_copy_1,
    __TestCode__testFunc_block_dispose_1
};

值得注意的是:copy再愈、dispose的實(shí)現(xiàn)函數(shù)

// copy 函數(shù)
static void __TestCode__testFunc_block_copy_1(struct __TestCode__testFunc_block_impl_1*dst, struct __TestCode__testFunc_block_impl_1*src)
{
    _Block_object_assign((void*)&dst->weakSelf, (void*)src->weakSelf, 3/*BLOCK_FIELD_IS_OBJECT*/);
    _Block_object_assign((void*)&dst->blockSelf, (void*)src->blockSelf, 8/*BLOCK_FIELD_IS_BYREF*/);
}

// dispose 函數(shù)
static void __TestCode__testFunc_block_dispose_1(struct __TestCode__testFunc_block_impl_1*src)
{
    _Block_object_dispose((void*)src->weakSelf, 3/*BLOCK_FIELD_IS_OBJECT*/);
    _Block_object_dispose((void*)src->blockSelf, 8/*BLOCK_FIELD_IS_BYREF*/);
}
a. 對(duì)weakSelf_Block_object_assign操作
void _Block_object_assign(void *destAddr, const void *object, const int flags) {
  
  // BLOCK_BYREF_CALLER block輔助函數(shù)調(diào)用(告訴內(nèi)部實(shí)現(xiàn)不要進(jìn)行retain或者copy)
    if ((flags & BLOCK_BYREF_CALLER) == BLOCK_BYREF_CALLER) { ... }
  // 被__block修飾的變量
    else if ((flags & BLOCK_FIELD_IS_BYREF) == BLOCK_FIELD_IS_BYREF)  { ... }
  // 是一個(gè)block
    else if ((flags & BLOCK_FIELD_IS_BLOCK) == BLOCK_FIELD_IS_BLOCK) { ... }
  
  // 是一個(gè)對(duì)象
    else if ((flags & BLOCK_FIELD_IS_OBJECT) == BLOCK_FIELD_IS_OBJECT) {
        _Block_retain_object(object);
        _Block_assign((void *)object, destAddr);
    }
}

即直接對(duì)對(duì)象進(jìn)行一個(gè)_Block_retain_object操作

但是發(fā)現(xiàn)在ARC下_Block_retain_object函數(shù)并沒有給對(duì)象的引用計(jì)數(shù)+1。

static void (*_Block_retain_object)(const void *ptr) = _Block_retain_object_default;
static void _Block_retain_object_default(const void *ptr) {
    if (!ptr) return;
}
b. 對(duì)blockSelf_Block_object_assign操作

最終會(huì)調(diào)用到_Block_byref_assign_copy函數(shù)

static void _Block_byref_assign_copy(void *dest, const void *arg, const int flags) {

    struct Block_byref **destp = (struct Block_byref **)dest;
    struct Block_byref *src = (struct Block_byref *)arg;

        //不需要做任何操作
    if (src->forwarding->flags & BLOCK_IS_GC) {
    }
  
        // 需要copy到堆區(qū) 并且需要操作引用計(jì)數(shù)
    else if ((src->forwarding->flags & BLOCK_REFCOUNT_MASK) == 0) {
        bool isWeak = ((flags & (BLOCK_FIELD_IS_BYREF|BLOCK_FIELD_IS_WEAK)) == (BLOCK_FIELD_IS_BYREF|BLOCK_FIELD_IS_WEAK));
      
        struct Block_byref *copy = (struct Block_byref *)_Block_allocator(src->size, false, isWeak);
        copy->flags = src->flags | _Byref_flag_initial_value;
        copy->forwarding = copy; 
        src->forwarding = copy;  
        copy->size = src->size;
      
        if (isWeak) {
            copy->isa = &_NSConcreteWeakBlockVariable;  
        }
        if (src->flags & BLOCK_HAS_COPY_DISPOSE) {
          /// 調(diào)用 __Block_byref_blockSelf_0 中的 __Block_byref_id_object_copy 函數(shù)
                    /// 執(zhí)行byref的byref_keep函數(shù)(即assign函數(shù)护戳,只是會(huì)加上BLOCK_BYREF_CALLER標(biāo)志)翎冲,管理捕獲的對(duì)象內(nèi)存
            copy->byref_keep = src->byref_keep;
            copy->byref_destroy = src->byref_destroy;
            (*src->byref_keep)(copy, src);
        }
        else { ... }
    }
    // 已經(jīng)復(fù)制到堆、只操作引用計(jì)數(shù)
    else if ((src->forwarding->flags & BLOCK_NEEDS_FREE) == BLOCK_NEEDS_FREE) { ... }
    _Block_assign(src->forwarding, (void **)destp);
}

值得注意的是在Block_private.h找到了這個(gè)結(jié)構(gòu):

struct Block_byref {
    void *isa;
    struct Block_byref *forwarding;
    volatile int32_t flags; // contains ref count
    uint32_t size;
};

struct Block_byref_2 {
    // requires BLOCK_BYREF_HAS_COPY_DISPOSE
    BlockByrefKeepFunction byref_keep;
    BlockByrefDestroyFunction byref_destroy;
};

struct Block_byref_3 {
    // requires BLOCK_BYREF_LAYOUT_EXTENDED
    const char *layout;
};

其實(shí)byref_keep就是blockSelf中的__Block_byref_id_object_copy也就是函數(shù)__Block_byref_id_object_copy_131

所以其調(diào)用為

static void __Block_byref_id_object_copy_131(void *dst, void *src) {
 _Block_object_assign((char*)dst + 40, *(void * ) ((char)src + 40), 131);
}
  // 譯為
static void __Block_byref_id_object_copy_131(__Block_byref_blockSelf_0 *dst, __Block_byref_blockSelf_0 *src) {
 _Block_object_assign(
   dst->blockSelf, 
   *(void * )(src->blockSelf), 
   BLOCK_FIELD_IS_OBJECT|BLOCK_FIELD_IS_CALLER
 );
}

繼續(xù)看_Block_object_assign

void _Block_object_assign(void *destAddr, const void *object, const int flags) {
  
  // BLOCK_BYREF_CALLER block輔助函數(shù)調(diào)用(告訴內(nèi)部實(shí)現(xiàn)不要進(jìn)行retain或者copy)
    if ((flags & BLOCK_BYREF_CALLER) == BLOCK_BYREF_CALLER) {
      //BLOCK_FIELD_IS_WEAK 被__weak修飾的變量媳荒,只能被輔助copy函數(shù)使用 
        if ((flags & BLOCK_FIELD_IS_WEAK) == BLOCK_FIELD_IS_WEAK) {
            _Block_assign_weak(object, destAddr);
        }
        else {
            _Block_assign((void *)object, destAddr);
        }
    }
    else if ((flags & BLOCK_FIELD_IS_BYREF) == BLOCK_FIELD_IS_BYREF)  { ... }
    else if ((flags & BLOCK_FIELD_IS_BLOCK) == BLOCK_FIELD_IS_BLOCK) { ... }
    else if ((flags & BLOCK_FIELD_IS_OBJECT) == BLOCK_FIELD_IS_OBJECT) { ... }
}
static void (*_Block_assign)(void *value, void **destptr) = _Block_assign_default;

static void _Block_assign_default(void *value, void **destptr) {
    *destptr = value;
}

運(yùn)行了_Block_assign函數(shù)抗悍,把棧區(qū)的__Block_byref_blockSelf_0 blockSelf賦值成了Block_byref copy

c. 對(duì)weakSelfdispose操作
static void __TestCode__testFunc_block_dispose_1(struct __TestCode__testFunc_block_impl_1*src) 
{
  _Block_object_dispose(
    (void*)src->self, 
    3/*BLOCK_FIELD_IS_OBJECT*/
  );
  _Block_object_dispose(
    (void*)src->blockSelf,
    8/*BLOCK_FIELD_IS_BYREF*/
  );
}

void _Block_object_dispose(const void *object, const int flags) {
    if (flags & BLOCK_FIELD_IS_BYREF)  { ... }
    else if ((flags & (BLOCK_FIELD_IS_BLOCK|BLOCK_BYREF_CALLER)) == BLOCK_FIELD_IS_BLOCK) {...}
    else if ((flags & (BLOCK_FIELD_IS_WEAK|BLOCK_FIELD_IS_BLOCK|BLOCK_BYREF_CALLER)) == BLOCK_FIELD_IS_OBJECT) {
        // 釋放block 引用的對(duì)象
        _Block_release_object(object);
    }
}
static void (*_Block_release_object)(const void *ptr) = _Block_release_object_default;
static void _Block_release_object_default(const void *ptr) {
    if (!ptr) return;
}

可以看到:最終會(huì)調(diào)用到_Block_release_object,內(nèi)部也是沒對(duì)引用計(jì)數(shù)進(jìn)行操作。

d. 對(duì)blockSelfdispose操作

其最終走到了_Block_byref_release函數(shù):

static void _Block_byref_release(const void *arg) {
    struct Block_byref *shared_struct = (struct Block_byref *)arg;
    int refcount;
    shared_struct = shared_struct->forwarding;
    if ((shared_struct->flags & BLOCK_NEEDS_FREE) == 0) {
        return; 
    }
    refcount = shared_struct->flags & BLOCK_REFCOUNT_MASK;
    if (refcount <= 0) {  }
    else if ((latching_decr_int(&shared_struct->flags) & BLOCK_REFCOUNT_MASK) == 0) {
    /// 主要調(diào)用了
        if (shared_struct->flags & BLOCK_HAS_COPY_DISPOSE) {
            (*shared_struct->byref_destroy)(shared_struct);
        }
        _Block_deallocator((struct Block_layout *)shared_struct);
    }
}

其中__block_release函數(shù)內(nèi)部主要是調(diào)用了(*shared_struct->byref_destroy)(shared_struct)

也就是 __Block_byref_blockSelf_0 *blockSelf 中的__Block_byref_id_object_dispose_131函數(shù)

static void __Block_byref_id_object_dispose_131(void *src) {
     _Block_object_dispose(*(void * *) ((char*)src + 40), 131);
}

///譯為:
static void __Block_byref_id_object_dispose_131(__Block_byref_blockSelf_0 *src) {
    
  _Block_object_dispose
   (
     *(void * *) (src->blockSelf), 
     BLOCK_FIELD_IS_OBJECT|BLOCK_FIELD_IS_CALLER
   );
}
e. __TestCode__testFunc_block_func_1

查看__TestCode__testFunc_block_func_1钳枕,函數(shù)中是如何創(chuàng)建第二層block222

{
  __strong typeof(weakSelf)strongSelf = weakSelf;
        void(^block222)(void) = ^{
            blockSelf = strongSelf;
            printf("\nblock測試代碼\n");
        };
        block222();
}

static void __TestCode__testFunc_block_func_1(struct __TestCode__testFunc_block_impl_1 *__cself) {
    
    __Block_byref_blockSelf_0 *blockSelf = __cself->blockSelf; // bound by ref
    TestCode *const __weak weakSelf = __cself->weakSelf; // bound by copy

    ///__strong typeof(weakSelf)strongSelf = weakSelf;
    __attribute__((objc_ownership(strong))) typeof(weakSelf)strongSelf = weakSelf;
    
    /// 創(chuàng)建block222 即:__TestCode__testFunc_block_impl_0結(jié)構(gòu)體
    void(*block222)(void) = ((void (*)())&__TestCode__testFunc_block_impl_0((void *)__TestCode__testFunc_block_func_0,&__TestCode__testFunc_block_desc_0_DATA,strongSelf,(__Block_byref_blockSelf_0 *)blockSelf,570425344));
  
    /// 調(diào)用: block222()
    ((void (*)(__block_impl *))((__block_impl *)block222)->FuncPtr)((__block_impl *)block222);
}

其中block222是一個(gè)__TestCode__testFunc_block_impl_0結(jié)構(gòu)體

4. __TestCode__testFunc_block_impl_0

struct __TestCode__testFunc_block_impl_0 {
  struct __block_impl impl;
  struct __TestCode__testFunc_block_desc_0* Desc;
    
  TestCode *const __strong strongSelf;
  __Block_byref_blockSelf_0 *blockSelf; // by ref
    
  __TestCode__testFunc_block_impl_0(
                                    void *fp,
                                    struct __TestCode__testFunc_block_desc_0 *desc,
                                    TestCode *const __strong _strongSelf,
                                    __Block_byref_blockSelf_0 *_blockSelf,
                                    int flags=0
                                    ) : strongSelf(_strongSelf), blockSelf(_blockSelf->__forwarding) {
    impl.isa = &_NSConcreteStackBlock;
    impl.Flags = flags;
    impl.FuncPtr = fp;
    Desc = desc;
  }
};

其結(jié)構(gòu)和__TestCode__testFunc_block_impl_1結(jié)構(gòu)相似缴渊。

只不過blockSelf就是上層block(即:block111)中的 blockSelf

值得注意的是這邊有個(gè)TestCode *const __strong strongSelf;

剩下的結(jié)構(gòu)與之前分析的結(jié)構(gòu)大同小異:

static void __TestCode__testFunc_block_func_0(struct __TestCode__testFunc_block_impl_0 *__cself) {
  __Block_byref_blockSelf_0 *blockSelf = __cself->blockSelf; // bound by ref
  TestCode *const __strong strongSelf = __cself->strongSelf; // bound by copy

            (blockSelf->__forwarding->blockSelf) = strongSelf;
            printf("\nblock測試代碼\n");
        }
static void __TestCode__testFunc_block_copy_0(struct __TestCode__testFunc_block_impl_0*dst, struct __TestCode__testFunc_block_impl_0*src) {_Block_object_assign((void*)&dst->blockSelf, (void*)src->blockSelf, 8/*BLOCK_FIELD_IS_BYREF*/);_Block_object_assign((void*)&dst->strongSelf, (void*)src->strongSelf, 3/*BLOCK_FIELD_IS_OBJECT*/);}

static void __TestCode__testFunc_block_dispose_0(struct __TestCode__testFunc_block_impl_0*src) {_Block_object_dispose((void*)src->blockSelf, 8/*BLOCK_FIELD_IS_BYREF*/);_Block_object_dispose((void*)src->strongSelf, 3/*BLOCK_FIELD_IS_OBJECT*/);}

static struct __TestCode__testFunc_block_desc_0 {
  size_t reserved;
  size_t Block_size;
  void (*copy)(struct __TestCode__testFunc_block_impl_0*, struct __TestCode__testFunc_block_impl_0*);
  void (*dispose)(struct __TestCode__testFunc_block_impl_0*);
} __TestCode__testFunc_block_desc_0_DATA = { 0, sizeof(struct __TestCode__testFunc_block_impl_0), __TestCode__testFunc_block_copy_0, __TestCode__testFunc_block_dispose_0};

三:持有變量引用計(jì)數(shù)操作:

既然在ARCcopydispose函數(shù)都沒有對(duì)引用計(jì)數(shù)做修改鱼炒,那么什么時(shí)候會(huì)對(duì)引用計(jì)數(shù)進(jìn)行操作?

通過對(duì)持有變量的分析衔沼、可以總結(jié)出以下特點(diǎn)

1. 用__strong 與 __weak修飾

- (void)testFunc {
    printf("\n Retain Count = %ld",CFGetRetainCount((__bridge CFTypeRef)(self)));
    
    __weak typeof (self)weakSelf1 = self;
    printf("\n 【__weak typeof (self)weakSelf】 Retain Count = %ld",CFGetRetainCount((__bridge CFTypeRef)(self)));
    
    __weak TestCode *weakSelf2 = self;
    printf("\n 【__weak TestCode *weakSelf2】 Retain Count = %ld",CFGetRetainCount((__bridge CFTypeRef)(self)));
    
    __strong typeof(self)strongSelf1 = self;
    printf("\n 【__strong typeof(self)strongSelf1】 Retain Count = %ld",CFGetRetainCount((__bridge CFTypeRef)(self)));
    
    __strong TestCode *strongSelf2 = self;
    printf("\n 【__strong TestCode *strongSelf2】 Retain Count = %ld",CFGetRetainCount((__bridge CFTypeRef)(self)));
    
    self.block111 = ^{
        [weakSelf1 class];
        [weakSelf2 class];
        [strongSelf1 class];
        [strongSelf2 class];
    };
}

/** log:
 Retain Count = 1
 【__weak typeof (self)weakSelf】 Retain Count = 1
 【__weak TestCode *weakSelf2】 Retain Count = 1
 【__strong typeof(self)strongSelf1】 Retain Count = 2
 【__strong TestCode *strongSelf2】 Retain Count = 3
*/

編譯后的代碼:

static void _I_TestCode_testFunc(TestCode * self, SEL _cmd) {
    printf("...");
    
      __attribute__((objc_ownership(weak))) typeof (self)weakSelf1 = self;  
    __attribute__((objc_ownership(weak))) TestCode *weakSelf2 = self;
  
    __attribute__((objc_ownership(strong))) typeof(self)strongSelf1 = self;
    __attribute__((objc_ownership(strong))) TestCode *strongSelf2 = self;

    ((void (*)(id, SEL, void (^ _Nonnull)()))(void *)objc_msgSend)((id)self, sel_registerName("setBlock111:"), ((void (*)())&__TestCode__testFunc_block_impl_0((void *)__TestCode__testFunc_block_func_0, &__TestCode__testFunc_block_desc_0_DATA, strongSelf1, strongSelf2, 570425344)));
}


struct __TestCode__testFunc_block_impl_0 {
  struct __block_impl impl;
  struct __TestCode__testFunc_block_desc_0* Desc;
 
  TestCode *const __weak weakSelf1;
  TestCode *__weak weakSelf2;
  
  __strong typeof (self) strongSelf1;
  TestCode *__strong strongSelf2;

  // 同名構(gòu)造函數(shù)
  __TestCode__testFunc_block_impl_0(...){ ... }
};

  1. __weak

    __weak TestCode *weakSelf1 = self__weak typeof(self)weakSelf2 = self

    最終都調(diào)用了__attribute__((objc_ownership(weak)))

    而且__TestCode__testFunc_block_impl_0中對(duì)weakSelf1weakSelf2都是弱引用

  2. __strong

    __strong typeof(self)strongSelf1 = self__strong TestCode *strongSelf2 = self

    最終都調(diào)用了__attribute__((objc_ownership(strong)))

    而且__TestCode__testFunc_block_impl_0中對(duì)strongSelf1strongSelf2都是強(qiáng)引用

2. 用__block修飾的對(duì)象

__block修飾的對(duì)象分成兩種寫法

  1. __block TestCode *blockSelf = weakSelf
  2. __block typeof(weakSelf)blockSelf2 = weakSelf

- (void)testFunc {
    printf("\n Retain Count = %ld",CFGetRetainCount((__bridge CFTypeRef)(self)));
    
    __weak typeof(self)weakSelf = self;
    
    __block TestCode *blockSelf1 = weakSelf;
    printf("\n 【__block TestCode *blockSelf1 = weakSelf】 Retain Count = %ld",CFGetRetainCount((__bridge CFTypeRef)(self)));
    
    __block typeof(weakSelf)blockSelf2 = weakSelf;
    printf("\n 【__block typeof(weakSelf)blockSelf2 = weakSelf】 Retain Count = %ld",CFGetRetainCount((__bridge CFTypeRef)(self)));
    
    self.block111 = ^{
        [blockSelf1 class];
        [blockSelf2 class];
    };
}

/**log:
 Retain Count = 1
 【__block TestCode *blockSelf1 = weakSelf】 Retain Count = 2
 【__block typeof(weakSelf)blockSelf2 = weakSelf】 Retain Count = 2
*/

編譯上述代碼:

struct __TestCode__testFunc_block_impl_0 {
  
  struct __block_impl impl;
  struct __TestCode__testFunc_block_desc_0* Desc;
    
  __Block_byref_blockSelf1_0 *blockSelf1; // by ref
  __Block_byref_blockSelf2_1 *blockSelf2; // by ref
  
    // 同名構(gòu)造函數(shù)
  __TestCode__testFunc_block_impl_0(...)  { ...  }
};

struct __Block_byref_blockSelf1_0 {
  void *__isa;
__Block_byref_blockSelf1_0 *__forwarding;
 int __flags;
 int __size;
 void (*__Block_byref_id_object_copy)(void*, void*);
 void (*__Block_byref_id_object_dispose)(void*);
 TestCode *__strong blockSelf1;
};

struct __Block_byref_blockSelf2_1 {
  void *__isa;
__Block_byref_blockSelf2_1 *__forwarding;
 int __flags;
 int __size;
 void (*__Block_byref_id_object_copy)(void*, void*);
 void (*__Block_byref_id_object_dispose)(void*);
 typeof (weakSelf) blockSelf2;
};

__TestCode__testFunc_block_impl_0中生成了兩個(gè)成員變量

  1. __block TestCode *blockSelf = weakSelf

    TestCode *__strong blockSelf1;對(duì)self進(jìn)行了強(qiáng)引用,從而self引用計(jì)數(shù)+1,從而產(chǎn)生循環(huán)引用昔瞧。

  2. __block typeof(weakSelf)blockSelf2 = weakSelf;

    typeof (weakSelf) blockSelf2 對(duì)self的引用為弱引用指蚁,引用計(jì)數(shù)沒有+1操作。

3. 補(bǔ)充:

  1. 在當(dāng)前作用域中自晰,對(duì)selfretainCount加1凝化,退出作用域后減一
    1. __block typeof(self)blockSelf = self;
    2. __block NSObject *blockSelf = self;
    3. __strong typeof (self)strongSelf = self;
    4. __strong NSObject *strongSelf = self;
  2. 對(duì)selfretainCount不作操作
    1. __weak typeof(self)weakSelf = self;
    2. __weak NSObject *weakSelf = self;

注意 :

用這些修飾語句對(duì)對(duì)象的引用計(jì)數(shù)只在當(dāng)前作用域有效。讓block產(chǎn)生循環(huán)引用的關(guān)鍵在于

__TestCode__testFunc_block_impl_0 block結(jié)構(gòu)體中對(duì)對(duì)象是否是強(qiáng)引用酬荞。

思考答案

@implementation TestCode
- (void)testFunc {
    @weakify(self)
    self.block111 = ^{
        @strongify(self);
        dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2.0 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
            if (self) {
                printf("\n\nstrongPerson1 Retain Count = %ld",CFGetRetainCount((__bridge CFTypeRef)(self)));
            }else{
                printf("self Retain Count = 0 \n");
            }
        });
    };
}

- (void)dealloc {
    printf("\n");
    printf("? 【dealloc】 Retain Count = 0");
}
@end

編譯后代碼:

/// block111結(jié)構(gòu)體
struct __TestCode__testFunc_block_impl_1 {
  struct __block_impl impl;
  struct __TestCode__testFunc_block_desc_1* Desc;
  
  TestCode *const __weak self_weak_;// 若引用
  
  __TestCode__testFunc_block_impl_1(void *fp, struct __TestCode__testFunc_block_desc_1 *desc, TestCode *const __weak _self_weak_, int flags=0) : self_weak_(_self_weak_) {
    impl.isa = &_NSConcreteStackBlock;
    impl.Flags = flags;
    impl.FuncPtr = fp;
    Desc = desc;
  }
};

///block111中儲(chǔ)存的代碼
static void __TestCode__testFunc_block_func_1(struct __TestCode__testFunc_block_impl_1 *__cself) {
  TestCode *const __weak self_weak_ = __cself->self_weak_; // bound by copy

        try {} catch (...) {}
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wshadow"
 __attribute__((objc_ownership(strong))) __typeof__(self) self = self_weak_;
#pragma clang diagnostic pop
;
        dispatch_after(dispatch_time((0ull), (int64_t)(2.0 * 1000000000ull)), dispatch_get_main_queue(), ((void (*)())&__TestCode__testFunc_block_impl_0((void *)__TestCode__testFunc_block_func_0, &__TestCode__testFunc_block_desc_0_DATA, self, 570425344)));
    }


/// block222結(jié)構(gòu)體
struct __TestCode__testFunc_block_impl_0 {
    
  struct __block_impl impl;
  struct __TestCode__testFunc_block_desc_0* Desc;
    
  __strong typeof (self) self;/// 強(qiáng)引用
    
  __TestCode__testFunc_block_impl_0(void *fp, struct __TestCode__testFunc_block_desc_0 *desc, __strong typeof (self) _self, int flags=0) : self(_self) {
    impl.isa = &_NSConcreteStackBlock;
    impl.Flags = flags;
    impl.FuncPtr = fp;
    Desc = desc;
  }
};

注意:以下block111是self所持有的block

  • 如果在block111 中對(duì) NSMutableArray *arrayM 進(jìn)行增刪元素, arrayM是否需要用__block修飾搓劫?

    答:不需要,因?yàn)椴]有修改arrayM指針?biāo)赶虻牡刂?/p>

  • block111 中對(duì)weakSelf進(jìn)行 __strong typeof(weakSelf) strongSelf = weakSelf 修飾

    • 如果block一直不調(diào)用混巧,那么self是否可以正常銷毀糟把?

      答:可以銷毀

      因?yàn)?code>block調(diào)用的時(shí)候,才會(huì)創(chuàng)建__TestCode__testFunc_block_impl_0

      使得__TestCode__testFunc_block_impl_0內(nèi)部對(duì)self進(jìn)行了強(qiáng)引用

      從而只要__TestCode__testFunc_block_impl_0不銷毀牲剃,self就無法銷毀

    • 當(dāng)運(yùn)行到__strong typeof(weakSelf) strongSelf = weakSelf的下一行時(shí),self引用計(jì)數(shù)最少是多少雄可?

      答:最少是2

      但是出了__strong typeof(weakSelf) strongSelf = weakSelf的作用域凿傅,self的引用計(jì)數(shù)就會(huì)自動(dòng)減1

    判斷void*是否為block類型

BOOL FBObjectIsBlock(void *object) {
    Class blockClass = _BlockClass();

    Class candidate = object_getClass((__bridge id)object);
    return [candidate isSubclassOfClass:blockClass];
}

參考文章

  1. 探索 Block 的本質(zhì)
  2. iOS底層原理總結(jié) - 探尋block的本質(zhì)(一)
  3. iOS底層原理總結(jié) - 探尋block的本質(zhì)(二)
  4. iOS Block Part6:block拷貝的實(shí)現(xiàn)
  5. OS - Block底層解析
  6. 一篇文章剖析block底層源碼以及Block.private
  7. Block_private.h
  8. runtime.c
  9. iOS 中的 block 是如何持有對(duì)象的

如果有不對(duì)的地方歡迎來噴~

郵箱:15076299703@163.com

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末缠犀,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子聪舒,更是在濱河造成了極大的恐慌辨液,老刑警劉巖,帶你破解...
    沈念sama閱讀 219,270評(píng)論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件箱残,死亡現(xiàn)場離奇詭異滔迈,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)被辑,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,489評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門燎悍,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人盼理,你說我怎么就攤上這事谈山。” “怎么了宏怔?”我有些...
    開封第一講書人閱讀 165,630評(píng)論 0 356
  • 文/不壞的土叔 我叫張陵奏路,是天一觀的道長。 經(jīng)常有香客問我臊诊,道長鸽粉,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,906評(píng)論 1 295
  • 正文 為了忘掉前任抓艳,我火速辦了婚禮触机,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘壶硅。我一直安慰自己威兜,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,928評(píng)論 6 392
  • 文/花漫 我一把揭開白布庐椒。 她就那樣靜靜地躺著椒舵,像睡著了一般。 火紅的嫁衣襯著肌膚如雪约谈。 梳的紋絲不亂的頭發(fā)上笔宿,一...
    開封第一講書人閱讀 51,718評(píng)論 1 305
  • 那天,我揣著相機(jī)與錄音棱诱,去河邊找鬼泼橘。 笑死,一個(gè)胖子當(dāng)著我的面吹牛迈勋,可吹牛的內(nèi)容都是我干的炬灭。 我是一名探鬼主播,決...
    沈念sama閱讀 40,442評(píng)論 3 420
  • 文/蒼蘭香墨 我猛地睜開眼靡菇,長吁一口氣:“原來是場噩夢啊……” “哼重归!你這毒婦竟也來了米愿?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,345評(píng)論 0 276
  • 序言:老撾萬榮一對(duì)情侶失蹤鼻吮,失蹤者是張志新(化名)和其女友劉穎育苟,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體椎木,經(jīng)...
    沈念sama閱讀 45,802評(píng)論 1 317
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡违柏,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,984評(píng)論 3 337
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了香椎。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片漱竖。...
    茶點(diǎn)故事閱讀 40,117評(píng)論 1 351
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖士鸥,靈堂內(nèi)的尸體忽然破棺而出闲孤,到底是詐尸還是另有隱情,我是刑警寧澤烤礁,帶...
    沈念sama閱讀 35,810評(píng)論 5 346
  • 正文 年R本政府宣布讼积,位于F島的核電站,受9級(jí)特大地震影響脚仔,放射性物質(zhì)發(fā)生泄漏勤众。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,462評(píng)論 3 331
  • 文/蒙蒙 一鲤脏、第九天 我趴在偏房一處隱蔽的房頂上張望们颜。 院中可真熱鬧,春花似錦猎醇、人聲如沸窥突。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,011評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽阻问。三九已至,卻和暖如春沦疾,著一層夾襖步出監(jiān)牢的瞬間称近,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,139評(píng)論 1 272
  • 我被黑心中介騙來泰國打工哮塞, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留刨秆,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 48,377評(píng)論 3 373
  • 正文 我出身青樓忆畅,卻偏偏與公主長得像衡未,于是被迫代替她去往敵國和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,060評(píng)論 2 355