OC中block的變量捕獲

block變量捕獲

在講解block變量的捕獲之前,我們先來看看OC中的變量大致分為哪幾類:

  • 局部變量
    • 自動變量
    • 靜態(tài)變量
  • 全局變量

我們在main函數(shù)內(nèi)創(chuàng)建一個auto變量age和一個static變量height,main函數(shù)外創(chuàng)建一個全局變量weight,代碼如下:

// 全局變量
int weight = 30;

int main(int argc, const char * argv[]) {
    @autoreleasepool {
        // insert code here...
        
        // 自動變量,默認省略了`auto`關鍵字
        int age = 10;
        
        // 靜態(tài)變量
        static int height = 20;
        
        void (^block)(void) = ^() {
            NSLog(@"%d", age); // 10
            NSLog(@"%d", height); // 200
            NSLog(@"%d", weight); // 300
        };
        
        age = 100;
        height = 200;
        weight = 300;
        
        block();
    }
    return 0;
}

我們執(zhí)行命令,將main.m轉換為c++代碼

int main(int argc, const char * argv[]) {
    /* @autoreleasepool */ { __AtAutoreleasePool __autoreleasepool; 

        int age = 10;
        static int height = 20;

        void (*block)(void) = &__main_block_impl_0(
                                                   __main_block_func_0,
                                                   &__main_block_desc_0_DATA,
                                                   age,
                                                   // 可以看到height這里是將變量的內(nèi)存地址作為參數(shù)傳遞
                                                   &height
                                                );
        age = 100;
        height = 200;
        weight = 300;

        block->FuncPtr(block);
    }
    return 0;
}

block結構體對象:

// 全局變量
int weight = 30;

struct __main_block_impl_0 {
  struct __block_impl impl;
  struct __main_block_desc_0* Desc;
  
  // auto變量
  int age;
  
  // static變量
  int *height;
  
  __main_block_impl_0(void *fp, struct __main_block_desc_0 *desc, int _age, int *_height, int flags=0) : age(_age), height(_height) {
    impl.isa = &_NSConcreteStackBlock;
    impl.Flags = flags;
    impl.FuncPtr = fp;
    Desc = desc;
  }
};

我們在創(chuàng)建一個Person類驗證變量的捕獲,代碼如下:

@interface Person : NSObject

@property (nonatomic, copy) NSString *name;

- (void)test;
@end

@implementation Person

- (void)test {

    void (^block)(void) = ^{
            // 注意:block內(nèi)雖然沒有寫self,但是_name等價于 self->_name
        NSLog(@"--%@", _name); // 111
    };
    
    block();
}
@end

我們修改下main函數(shù)代碼如下:

int main(int argc, const char * argv[]) {
    @autoreleasepool {
        // insert code here...
        
        Person *person = [[Person alloc] init];
        person.name = @"111";
        
        [person test];
    }
    return 0;
}

然后我們將Person.m文件轉換為c++代碼如下:

test函數(shù):

/**
    這里我們發(fā)現(xiàn)test函數(shù)默認有兩個參數(shù)`self`和_cmd,這兩個參數(shù)是函數(shù)的默認隱式參數(shù)。
    self:調用當前函數(shù)的對象
    _cmd:函數(shù)名
*/
static void _I_Person_test(Person * self, SEL _cmd) {

    void (*block)(void) = &__Person__test_block_impl_0(
                                                       __Person__test_block_func_0,
                                                       &__Person__test_block_desc_0_DATA,
                                                       self,
                                                       570425344
                                                       );
    block->FuncPtr(block);
}

__Person__test_block_impl_0block結構體:

struct __Person__test_block_impl_0 {
  struct __block_impl impl;
  struct __Person__test_block_desc_0* Desc;
  
  // 將當前Person對象self捕獲到block結構體內(nèi)
  Person *self;
  
  __Person__test_block_impl_0(void *fp, struct __Person__test_block_desc_0 *desc, Person *_self, int flags=0) : self(_self) {
    impl.isa = &_NSConcreteStackBlock;
    impl.Flags = flags;
    impl.FuncPtr = fp;
    Desc = desc;
  }
};

從上面轉換的底層c++代碼分析,我們可以得出結論入下圖所示:

image

講解示例Demo地址:https://github.com/guangqiang-liu/06.1-BlockDemo1

更多文章

最后編輯于
?著作權歸作者所有,轉載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

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