iOS底層 -- Blcok本質(zhì)之__Block修飾符

一、__Block修飾auto變量

  • __block可以用于解決block內(nèi)部無(wú)法修改auto變量值的問(wèn)題
  • __block不能修飾全局變量、靜態(tài)變量(static)

定義一個(gè)__block修飾的auto變量

Block block;
__block int age = 10; 
block = ^{
    age = 20;
    NSLog(@"%d", age);
};
block();

編譯器會(huì)將__block變量包裝成一個(gè)對(duì)象(結(jié)構(gòu)體)

struct __main_block_impl_0 {
  struct __block_impl impl;
  struct __main_block_desc_0* Desc;
  __Block_byref_age_0 *age; // by ref
  __main_block_impl_0(void *fp, struct __main_block_desc_0 *desc, __Block_byref_age_0 *_age, int flags=0) : age(_age->__forwarding) {
    impl.isa = &_NSConcreteStackBlock;
    impl.Flags = flags;
    impl.FuncPtr = fp;
    Desc = desc;
  }
};

struct __Block_byref_age_0 {
 void *__isa;   // isa指針
 __Block_byref_age_0 *__forwarding; // 指向自身的指針
 int __flags;
 int __size; // 結(jié)構(gòu)體的大小
 int age;    // auto變量的值
};

二、__block內(nèi)存管理

1.當(dāng)block在棧上時(shí),并不會(huì)對(duì)__block變量產(chǎn)生強(qiáng)引用

2.當(dāng)block被拷貝到堆上

  • 會(huì)調(diào)用block內(nèi)部的copy函數(shù)
  • copy函數(shù)內(nèi)部會(huì)調(diào)用_Block_object_assign函數(shù)
  • _Block_object_assign函數(shù)會(huì)對(duì)__block變量形成強(qiáng)引用(retain)
static void __main_block_copy_0(struct __main_block_impl_0*dst, struct __main_block_impl_0*src) {
    _Block_object_assign((void*)&dst->objc, (void*)src->objc, 3/*BLOCK_FIELD_IS_OBJECT*/);
}

3.當(dāng)block從堆中移除時(shí)

  • 會(huì)調(diào)用block內(nèi)部的dispose函數(shù)
  • dispose函數(shù)內(nèi)部會(huì)調(diào)用_Block_object_dispose函數(shù)
  • _Block_object_dispose函數(shù)會(huì)自動(dòng)釋放指向的對(duì)象(release)
static void __main_block_dispose_0(struct __main_block_impl_0*src) {
    _Block_object_dispose((void*)src->objc, 3/*BLOCK_FIELD_IS_OBJECT*/);
}

三、_forwarding指針的作用

復(fù)制之前:
age(棧區(qū)age結(jié)構(gòu)體)->_forwarding(指向自己的指針)->age(age成員變量值)

復(fù)制之后:
age(棧區(qū)age結(jié)構(gòu)體)->_forwarding(指向堆區(qū)age結(jié)構(gòu)體)->age(age成員變量值)

四、__block修飾對(duì)象類(lèi)型

1.當(dāng)__block變量在棧上時(shí),不會(huì)對(duì)指向的對(duì)象產(chǎn)生強(qiáng)引用

2.當(dāng)__block變量被copy到堆時(shí)

  • 會(huì)調(diào)用__block變量?jī)?nèi)部的copy函數(shù)
  • copy函數(shù)內(nèi)部會(huì)調(diào)用_Block_object_assign函數(shù)
  • _Block_object_assign函數(shù)會(huì)根據(jù)所指向?qū)ο蟮男揎椃╛_strong、__weak、__unsafe_unretained)做出相應(yīng)的操作,形成強(qiáng)引用(retain)或者弱引用(注意:這里僅限于ARC時(shí)會(huì)retain,MRC時(shí)不會(huì)retain)

強(qiáng)引用:

Block block;
__block Person *person = [[Person alloc] init];
block = ^{
    NSLog(@"%@", person);
};

struct __Block_byref_person_0 {
  void *__isa;
  __Block_byref_person_0 *__forwarding;
  int __flags;
  nt __size;
  void (*__Block_byref_id_object_copy)(void*, void*);//從棧上復(fù)制到堆上要進(jìn)行的操作
  void (*__Block_byref_id_object_dispose)(void*);//從堆上移除要進(jìn)行的操作
  Person *person;//強(qiáng)引用
};

弱引用:

Block block;
Person *person0 = [[Person alloc] init];
__block __weak Person *person = person0;
block = ^{
    NSLog(@"%@", person);
};

struct __Block_byref_person_0 {
  void *__isa;
  __Block_byref_person_0 *__forwarding;
  int __flags;
  int __size;
  void (*__Block_byref_id_object_copy)(void*, void*);//從棧上復(fù)制到堆上要進(jìn)行的操作
  void (*__Block_byref_id_object_dispose)(void*);//從堆上移除要進(jìn)行的操作
  Person *__weak person;//弱引用
};

3.當(dāng)__block變量從堆上移除

  • 會(huì)調(diào)用__block變量?jī)?nèi)部的dispose函數(shù)
  • dispose函數(shù)內(nèi)部會(huì)調(diào)用_Block_object_dispose函數(shù)
  • _Block_object_dispose函數(shù)會(huì)自動(dòng)釋放指向的對(duì)象(release)
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

友情鏈接更多精彩內(nèi)容