iOS block 再次探祕

__block 之於數組

  • 加不加block都行,推薦不加
  • 加了只是裏面多了一個結構體,然後發現還是往哪個結構體裏面的arr發消息,不加就是直接給arr發消息
#import <Foundation/Foundation.h>
int main(int argc, char * argv[]) {
    @autoreleasepool {
         NSMutableArray *arr = [NSMutableArray arrayWithObjects:@"1",@"2",@"3", nil];
        void(^block)(void) = ^{
            [arr addObject:@"4"];
        };
        block();
    }
}

clang -rewrite-objc main.m 後

struct __main_block_impl_0 {
  struct __block_impl impl;
  struct __main_block_desc_0* Desc;
  NSMutableArray *arr;
  __main_block_impl_0(void *fp, struct __main_block_desc_0 *desc, NSMutableArray *_arr, int flags=0) : arr(_arr) {
    impl.isa = &_NSConcreteStackBlock;
    impl.Flags = flags;
    impl.FuncPtr = fp;
    Desc = desc;
  }
};
static void __main_block_func_0(struct __main_block_impl_0 *__cself) {
  NSMutableArray *arr = __cself->arr; // bound by copy //

            ((void (*)(id, SEL, ObjectType _Nonnull))(void *)objc_msgSend)((id)arr, sel_registerName("addObject:"), (id _Nonnull)(NSString *)&__NSConstantStringImpl__var_folders_tj_wxmdttwx7bv3h31ynxs4qc5m0000gn_T_main_af0c47_mi_3);
        }
static void __main_block_copy_0(struct __main_block_impl_0*dst, struct __main_block_impl_0*src) {_Block_object_assign((void*)&dst->arr, (void*)src->arr, 3/*BLOCK_FIELD_IS_OBJECT*/);}

static void __main_block_dispose_0(struct __main_block_impl_0*src) {_Block_object_dispose((void*)src->arr, 3/*BLOCK_FIELD_IS_OBJECT*/);}

static struct __main_block_desc_0 {
  size_t reserved;
  size_t Block_size;
  void (*copy)(struct __main_block_impl_0*, struct __main_block_impl_0*);
  void (*dispose)(struct __main_block_impl_0*);
} __main_block_desc_0_DATA = { 0, sizeof(struct __main_block_impl_0), __main_block_copy_0, __main_block_dispose_0};
int main(int argc, char * argv[]) {
    /* @autoreleasepool */ { __AtAutoreleasePool __autoreleasepool; 
         NSMutableArray *arr = ((NSMutableArray * _Nonnull (*)(id, SEL, ObjectType _Nonnull, ...))(void *)objc_msgSend)((id)objc_getClass("NSMutableArray"), sel_registerName("arrayWithObjects:"), (id _Nonnull)(NSString *)&__NSConstantStringImpl__var_folders_tj_wxmdttwx7bv3h31ynxs4qc5m0000gn_T_main_af0c47_mi_0, (NSString *)&__NSConstantStringImpl__var_folders_tj_wxmdttwx7bv3h31ynxs4qc5m0000gn_T_main_af0c47_mi_1, (NSString *)&__NSConstantStringImpl__var_folders_tj_wxmdttwx7bv3h31ynxs4qc5m0000gn_T_main_af0c47_mi_2, __null);
        void(*block)(void) = ((void (*)())&__main_block_impl_0((void *)__main_block_func_0, &__main_block_desc_0_DATA, arr, 570425344));
        ((void (*)(__block_impl *))((__block_impl *)block)->FuncPtr)((__block_impl *)block);
    }
}
static struct IMAGE_INFO { unsigned version; unsigned flag; } _OBJC_IMAGE_INFO = { 0, 2 };

arrblock\color{red}{注意這裏arr也是指針,外面不能賦值的原因,如果賦值了你只改變了block裏面的值,並沒有改變外面的值}

#import <Foundation/Foundation.h>
int main(int argc, char * argv[]) {
    @autoreleasepool {
        __block NSMutableArray *arr = [NSMutableArray arrayWithObjects:@"1",@"2",@"3", nil];
        void(^block)(void) = ^{
            [arr addObject:@"4"];
        };
        block();
    }
}

clang -rewrite-objc main.m 後


struct __Block_byref_arr_0 {
  void *__isa;
__Block_byref_arr_0 *__forwarding;
 int __flags;
 int __size;
 void (*__Block_byref_id_object_copy)(void*, void*);
 void (*__Block_byref_id_object_dispose)(void*);
 NSMutableArray *arr;
};

struct __main_block_impl_0 {
  struct __block_impl impl;
  struct __main_block_desc_0* Desc;
  __Block_byref_arr_0 *arr; // by ref
  __main_block_impl_0(void *fp, struct __main_block_desc_0 *desc, __Block_byref_arr_0 *_arr, int flags=0) : arr(_arr->__forwarding) {
    impl.isa = &_NSConcreteStackBlock;
    impl.Flags = flags;
    impl.FuncPtr = fp;
    Desc = desc;
  }
};
static void __main_block_func_0(struct __main_block_impl_0 *__cself) {
  __Block_byref_arr_0 *arr = __cself->arr; // bound by ref
            ((void (*)(id, SEL, ObjectType _Nonnull))(void *)objc_msgSend)((id)(arr->__forwarding->arr), sel_registerName("addObject:"), (id _Nonnull)(NSString *)&__NSConstantStringImpl__var_folders_tj_wxmdttwx7bv3h31ynxs4qc5m0000gn_T_main_c4a3eb_mi_3);
        }
static void __main_block_copy_0(struct __main_block_impl_0*dst, struct __main_block_impl_0*src) {_Block_object_assign((void*)&dst->arr, (void*)src->arr, 8/*BLOCK_FIELD_IS_BYREF*/);}

static void __main_block_dispose_0(struct __main_block_impl_0*src) {_Block_object_dispose((void*)src->arr, 8/*BLOCK_FIELD_IS_BYREF*/);}

static struct __main_block_desc_0 {
  size_t reserved;
  size_t Block_size;
  void (*copy)(struct __main_block_impl_0*, struct __main_block_impl_0*);
  void (*dispose)(struct __main_block_impl_0*);
} __main_block_desc_0_DATA = { 0, sizeof(struct __main_block_impl_0), __main_block_copy_0, __main_block_dispose_0};
int main(int argc, char * argv[]) {
    /* @autoreleasepool */ { __AtAutoreleasePool __autoreleasepool; 
        __attribute__((__blocks__(byref))) __Block_byref_arr_0 arr = {(void*)0,(__Block_byref_arr_0 *)&arr, 33554432, sizeof(__Block_byref_arr_0), __Block_byref_id_object_copy_131, __Block_byref_id_object_dispose_131, ((NSMutableArray * _Nonnull (*)(id, SEL, ObjectType _Nonnull, ...))(void *)objc_msgSend)((id)objc_getClass("NSMutableArray"), sel_registerName("arrayWithObjects:"), (id _Nonnull)(NSString *)&__NSConstantStringImpl__var_folders_tj_wxmdttwx7bv3h31ynxs4qc5m0000gn_T_main_c4a3eb_mi_0, (NSString *)&__NSConstantStringImpl__var_folders_tj_wxmdttwx7bv3h31ynxs4qc5m0000gn_T_main_c4a3eb_mi_1, (NSString *)&__NSConstantStringImpl__var_folders_tj_wxmdttwx7bv3h31ynxs4qc5m0000gn_T_main_c4a3eb_mi_2, __null)};
        void(*block)(void) = ((void (*)())&__main_block_impl_0((void *)__main_block_func_0, &__main_block_desc_0_DATA, (__Block_byref_arr_0 *)&arr, 570425344));
        ((void (*)(__block_impl *))((__block_impl *)block)->FuncPtr)((__block_impl *)block);
    }
}
static struct IMAGE_INFO { unsigned version; unsigned flag; } _OBJC_IMAGE_INFO = { 0, 2 };
    
  • arr=nilblockarr\color{red}{ 爲什麼這裏就能在更改設置arr = nil ,下劃線block 添加後,arr裏面和外面是一個指針,也不是,這句話表述有問題,內外指針有關聯,但不是一個指針,指向的內容相同}

block 之於常用變量

#import <Foundation/Foundation.h>
int main(int argc, char * argv[]) {
    @autoreleasepool {
        NSInteger i = 1;
        void(^block)(void) = ^{
            NSLog(@"print i value %d",i);
        };
        block();
    }
}

//simpel:

   struct __main_block_impl_0 {
  struct __block_impl impl;
  struct __main_block_desc_0* Desc;
  NSInteger i;
  __main_block_impl_0(void *fp, struct __main_block_desc_0 *desc, NSInteger _i, int flags=0) : i(_i) {
    impl.isa = &_NSConcreteStackBlock;
    impl.Flags = flags;
    impl.FuncPtr = fp;
    Desc = desc;
  }
};
static void __main_block_func_0(struct __main_block_impl_0 *__cself) {
  NSInteger i = __cself->i; // bound by copy

            NSLog((NSString *)&__NSConstantStringImpl__var_folders_tj_wxmdttwx7bv3h31ynxs4qc5m0000gn_T_main_ac2ab8_mi_0,i);
        }

static struct __main_block_desc_0 {
  size_t reserved;
  size_t Block_size;
} __main_block_desc_0_DATA = { 0, sizeof(struct __main_block_impl_0)};
int main(int argc, char * argv[]) {
    /* @autoreleasepool */ { __AtAutoreleasePool __autoreleasepool; 
        NSInteger i = 1;
        void(*block)(void) = ((void (*)())&__main_block_impl_0((void *)__main_block_func_0, &__main_block_desc_0_DATA, i));
        ((void (*)(__block_impl *))((__block_impl *)block)->FuncPtr)((__block_impl *)block);
    }
}
static struct IMAGE_INFO { unsigned version; unsigned flag; } _OBJC_IMAGE_INFO = { 0, 2 };

#import <Foundation/Foundation.h>
int main(int argc, char * argv[]) {
    @autoreleasepool {
       __block NSInteger i = 1;
        void(^block)(void) = ^{
            NSLog(@"print i value %d",i);
        };
        block();
    }
}

///複雜的

struct __Block_byref_i_0 {
  void *__isa;
__Block_byref_i_0 *__forwarding;
 int __flags;
 int __size;
 NSInteger i;
};

struct __main_block_impl_0 {
  struct __block_impl impl;
  struct __main_block_desc_0* Desc;
  __Block_byref_i_0 *i; // by ref
  __main_block_impl_0(void *fp, struct __main_block_desc_0 *desc, __Block_byref_i_0 *_i, int flags=0) : i(_i->__forwarding) {
    impl.isa = &_NSConcreteStackBlock;
    impl.Flags = flags;
    impl.FuncPtr = fp;
    Desc = desc;
  }
};
static void __main_block_func_0(struct __main_block_impl_0 *__cself) {
  __Block_byref_i_0 *i = __cself->i; // bound by ref

            NSLog((NSString *)&__NSConstantStringImpl__var_folders_tj_wxmdttwx7bv3h31ynxs4qc5m0000gn_T_main_d33923_mi_0,(i->__forwarding->i));
        }
static void __main_block_copy_0(struct __main_block_impl_0*dst, struct __main_block_impl_0*src) {_Block_object_assign((void*)&dst->i, (void*)src->i, 8/*BLOCK_FIELD_IS_BYREF*/);}

static void __main_block_dispose_0(struct __main_block_impl_0*src) {_Block_object_dispose((void*)src->i, 8/*BLOCK_FIELD_IS_BYREF*/);}

static struct __main_block_desc_0 {
  size_t reserved;
  size_t Block_size;
  void (*copy)(struct __main_block_impl_0*, struct __main_block_impl_0*);
  void (*dispose)(struct __main_block_impl_0*);
} __main_block_desc_0_DATA = { 0, sizeof(struct __main_block_impl_0), __main_block_copy_0, __main_block_dispose_0};
int main(int argc, char * argv[]) {
    /* @autoreleasepool */ { __AtAutoreleasePool __autoreleasepool; 
       __attribute__((__blocks__(byref))) __Block_byref_i_0 i = {(void*)0,(__Block_byref_i_0 *)&i, 0, sizeof(__Block_byref_i_0), 1};
        void(*block)(void) = ((void (*)())&__main_block_impl_0((void *)__main_block_func_0, &__main_block_desc_0_DATA, (__Block_byref_i_0 *)&i, 570425344));
        ((void (*)(__block_impl *))((__block_impl *)block)->FuncPtr)((__block_impl *)block);
    }
}
static struct IMAGE_INFO { unsigned version; unsigned flag; } _OBJC_IMAGE_INFO = { 0, 2 };

block之於普通對象NSObject

加了關鍵字__block

#import <Foundation/Foundation.h>
int main(int argc, char * argv[]) {
    @autoreleasepool {
       __block  NSObject *object = [[NSObject alloc] init];
        void(^block)(void) = ^{
            NSLog(@"print %@",object);
        };
        block();
    }
}

struct __Block_byref_object_0 {
  void *__isa;
__Block_byref_object_0 *__forwarding;
 int __flags;
 int __size;
 void (*__Block_byref_id_object_copy)(void*, void*);
 void (*__Block_byref_id_object_dispose)(void*);
 NSObject *object;
};

struct __main_block_impl_0 {
  struct __block_impl impl;
  struct __main_block_desc_0* Desc;
  __Block_byref_object_0 *object; // by ref
  __main_block_impl_0(void *fp, struct __main_block_desc_0 *desc, __Block_byref_object_0 *_object, int flags=0) : object(_object->__forwarding) {
    impl.isa = &_NSConcreteStackBlock;
    impl.Flags = flags;
    impl.FuncPtr = fp;
    Desc = desc;
  }
};
static void __main_block_func_0(struct __main_block_impl_0 *__cself) {
  __Block_byref_object_0 *object = __cself->object; // bound by ref

            NSLog((NSString *)&__NSConstantStringImpl__var_folders_tj_wxmdttwx7bv3h31ynxs4qc5m0000gn_T_main_602bf3_mi_0,(object->__forwarding->object));
        }
static void __main_block_copy_0(struct __main_block_impl_0*dst, struct __main_block_impl_0*src) {_Block_object_assign((void*)&dst->object, (void*)src->object, 8/*BLOCK_FIELD_IS_BYREF*/);}

static void __main_block_dispose_0(struct __main_block_impl_0*src) {_Block_object_dispose((void*)src->object, 8/*BLOCK_FIELD_IS_BYREF*/);}

static struct __main_block_desc_0 {
  size_t reserved;
  size_t Block_size;
  void (*copy)(struct __main_block_impl_0*, struct __main_block_impl_0*);
  void (*dispose)(struct __main_block_impl_0*);
} __main_block_desc_0_DATA = { 0, sizeof(struct __main_block_impl_0), __main_block_copy_0, __main_block_dispose_0};
int main(int argc, char * argv[]) {
    /* @autoreleasepool */ { __AtAutoreleasePool __autoreleasepool; 
       __attribute__((__blocks__(byref))) __Block_byref_object_0 object = {(void*)0,(__Block_byref_object_0 *)&object, 33554432, sizeof(__Block_byref_object_0), __Block_byref_id_object_copy_131, __Block_byref_id_object_dispose_131, ((NSObject *(*)(id, SEL))(void *)objc_msgSend)((id)((NSObject *(*)(id, SEL))(void *)objc_msgSend)((id)objc_getClass("NSObject"), sel_registerName("alloc")), sel_registerName("init"))};
        void(*block)(void) = ((void (*)())&__main_block_impl_0((void *)__main_block_func_0, &__main_block_desc_0_DATA, (__Block_byref_object_0 *)&object, 570425344));
        ((void (*)(__block_impl *))((__block_impl *)block)->FuncPtr)((__block_impl *)block);
    }
}
static struct IMAGE_INFO { unsigned version; unsigned flag; } _OBJC_IMAGE_INFO = { 0, 2 };
#import <Foundation/Foundation.h>
int main(int argc, char * argv[]) {
    @autoreleasepool {
         NSObject *object = [[NSObject alloc] init];
        void(^block)(void) = ^{
            NSLog(@"print %@",object);
        };
        block();
    }
}
//old
struct __main_block_impl_0 {
  struct __block_impl impl;
  struct __main_block_desc_0* Desc;
  NSObject *object;
  __main_block_impl_0(void *fp, struct __main_block_desc_0 *desc, NSObject *_object, int flags=0) : object(_object) {
    impl.isa = &_NSConcreteStackBlock;
    impl.Flags = flags;
    impl.FuncPtr = fp;
    Desc = desc;
  }
};
static void __main_block_func_0(struct __main_block_impl_0 *__cself) {
  NSObject *object = __cself->object; // bound by copy

            NSLog((NSString *)&__NSConstantStringImpl__var_folders_tj_wxmdttwx7bv3h31ynxs4qc5m0000gn_T_main_81d78e_mi_0,object);
        }
static void __main_block_copy_0(struct __main_block_impl_0*dst, struct __main_block_impl_0*src) {_Block_object_assign((void*)&dst->object, (void*)src->object, 3/*BLOCK_FIELD_IS_OBJECT*/);}

static void __main_block_dispose_0(struct __main_block_impl_0*src) {_Block_object_dispose((void*)src->object, 3/*BLOCK_FIELD_IS_OBJECT*/);}

static struct __main_block_desc_0 {
  size_t reserved;
  size_t Block_size;
  void (*copy)(struct __main_block_impl_0*, struct __main_block_impl_0*);
  void (*dispose)(struct __main_block_impl_0*);
} __main_block_desc_0_DATA = { 0, sizeof(struct __main_block_impl_0), __main_block_copy_0, __main_block_dispose_0};
int main(int argc, char * argv[]) {
    /* @autoreleasepool */ { __AtAutoreleasePool __autoreleasepool; 
        NSObject *object = ((NSObject *(*)(id, SEL))(void *)objc_msgSend)((id)((NSObject *(*)(id, SEL))(void *)objc_msgSend)((id)objc_getClass("NSObject"), sel_registerName("alloc")), sel_registerName("init"));
        void(*block)(void) = ((void (*)())&__main_block_impl_0((void *)__main_block_func_0, &__main_block_desc_0_DATA, object, 570425344));
        ((void (*)(__block_impl *))((__block_impl *)block)->FuncPtr)((__block_impl *)block);
    }
}
static struct IMAGE_INFO { unsigned version; unsigned flag; } _OBJC_IMAGE_INFO = { 0, 2 };

筆記

1、這裏值得說明的一點是,如果Block外面還有很多自動變量,靜態變量,等等,這些變量在Block裏面並不會被使用到。那麼這些變量並不會被Block捕獲進來,也就是說並不會在構造函數裏面傳入它們的值。
Block捕獲外部變量僅僅只捕獲Block閉包裏面會用到的值,其他用不到的值,它並不會去捕獲。
2、我們可以發現,系統自動給我們加上的註釋,bound by copy,自動變量val雖然被捕獲進來了,但是是用 __cself->val來訪問的。Block僅僅捕獲了val的值,並沒有捕獲val的內存地址。所以在__main_block_func_0這個函數中即使我們重寫這個自動變量val的值,依舊沒法去改變Block外面自動變量val的值。
因爲修改裏面的值變成了修改裏面局部變量值而已了
3、Block捕獲的外部變量可以改變值的是靜態變量,靜態全局變量,全局變量。上面例子也都證明過了。
4、總結一下在Block中改變變量值有2種方式,一是傳遞內存地址指針到Block中,二是改變存儲區方式(__block)。
NSMutableArray *arr ,NSObject *objc ,NSMutableString *str 這些都是指針啊,但是這些指針是指向內容的指針,不是指針的地址,指針地址是&arr和&objc 、&str等
5、arc環境下,編譯器會自動的判斷,把block自動的從棧copy到堆
6、the block’s flags includes BLOCK_NEEDS_FREE then the block is a heap block (you’ll see why shortly). In this case, all that needs doing is the reference count needs incrementing and then the same block returned.
如果需要釋放,我們做的,就是增加引用計數
7、If the block is a global block (recall these from episode 1) then nothing needs doing and the same block is returned. This is because global blocks are effectively singletons.
全局block是全局單例
8、copy三步驟
如果需要free的,證明就是堆的,直接加1就行
如果是global ,global是全局單例,無需處理,直接返回就行。
除了這兩種情況,剩下的就是stack 了,需要重新分配內存
9、release 堆上會釋放
we made it here and the block is global, then do nothing
但如果是global就不釋放了

最後總結

1、NSMutableString , NSMutableArray, NSObject 可以直接傳入無需加__block,我們可以在裏面可以做如下修改:
修改string的值,array增加元素,減掉元素,object更改屬性的值,但是這些都不能賦值nil
2、靜態全局變量,靜態變量能不加__block,便能修改它們的值。
3、如果要將NSMutableString , NSMutableArray, NSObject置換爲nil,或者修改局部變量的值,需要用到__block
4、bound by copy 和 bound by ref
ref 指的事reference ,是指針拷貝, bound by ref 是指針拷貝,bound by copy是值拷貝。
這麼說可能是問題,待驗證。
5、而且如果此時在Block裏面改變a的值是會報錯,因爲普通變量的值傳遞爲複製,所有Block裏的a只是copy過去的a的值,在Block裏改變a的值也不會影響外面,編譯器避免這個錯誤就報錯。同樣的,捕獲對象時也是對指針的copy,生成一個指針指向obj對象,所以如果在Block中直接讓obj指針指向另外一個對象也會報錯。這點編譯器已經加了註釋// bound by copy。
第五點來源於
作者:WhiteZero
鏈接:https://www.jianshu.com/p/d96d27819679
6、block裏面說不加__block改變不了值,這個值指的是 指針指向的地址不能變,地址裏面的內容是可以變的
Bluce li
7、爲什麼不能在外面賦值,賦的值只是改變了block對象裏面的值,沒改變外面的值。
8、Block不允許修改外部變量的值,這裏所說的外部變量的值,指的是棧中指針的內存地址。\color{red}{棧區是紅燈區,堆區纔是綠燈區}。這句話摘自github一個有名的面試題
9、加了__block後,外面的變量一旦被block俘獲進去,這個變量就不再是之前的那個變量了,它的的棧內存地址會變了,其實已經成了一個新的變量了。

自問自答

1、爲什麼object、mutableStr、mutableArr增加元素、或者改變屬性值就行,但是賦值爲nil就不行呢
因爲賦值nil改變原先指向指針的指針的方向就是(&object)
2、爲什麼數組print arr 和print &arr不一樣呢
arr指向的是內容的地址,存放在堆,&arr指向指針arr的地址,存放在棧,這句話有可能錯
3、文中說傳入指針或者傳入__block就能更改,但實際,object、mutableStr、mutableArr都是指針啊,都不能賦值爲nil,說法有問題啊
只能改內容,不能改外面指針指向
4、實例和Class裏面都有實例變量,那變量到底放哪裏呢
猜測,變量在實例裏面,屬性在Class裏面呢
nsobject_impl結構體放了父類以及本類的實例變量,但是Class結構體只放了本類的實例變量
5、有沒有什麼辦法打印Class isa裏面究竟有什麼實例變量
有用runtime
6、爲什麼加了__block就能改變指針的值了呢
外面的arr指針和block內部的指針arr是一個哦,因爲傳入的是一個指針
7、從哪裏可以看出,哪裏拷貝了,系統自行拷貝嗎?
block轉爲函數指針時,傳入了這個結構體,這個結構體,裏面有copy 和dispose方法
__main_block_desc_0_DATA
8、經典 review qusetion2 38,very good

stack、malloc、global block區分

block分類,先後區分邏輯是gloabal、stack、malloc
注意:global:void (^stackBlock)() = ^{}; clang是stack
malloc:block爲strong類型,且捕獲了外部變量時。clang是stack
這兩種類型用clang看都是stack,但其實分別是global和malloc。有人(唐巧)說這是clang和llvm編譯方式不一樣,待驗證,期待更好的解釋。我猜測也是的,你能看到copy 的調用嗎,看不到,我猜clang只會給你大概的一點。

調試命令

//打印某個對象的引用計數
_objc_rootRetainCount(obj)
//打印自動緩存池所有的對象
_objc_autoreleasePoolPrint()

特別注意

如果我們想用clang 一個A文件,這個文件裏面有很多的其他文件,怎麼辦呢,直接cd進入這個A文件目錄(這個目錄當然也包含A文件需要的文件),直接用
xcrun -sdk iphoneos clang -arch arm64 -rewrite-objc A.m -o A.cpp

優秀文章(部分觀點引自下面文章)

優秀未讀文章

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章