2023年7月14日发(作者:)
OC中的block我们都知道block在oc中是很常⽤的,随处可见,越来越多的原先delegate的实现现在都⽤block去处理了,可见block的重要性。那么什么是block呢?block在使⽤的时候要注意什么呢?直接show code,看看底层block到底是变成了啥数据结果的/*block 被编译成了结构体,根据block捕获变量的情况,会有不同的情况。struct Block_layout和struct Block_descriptor_1是⼀定存在的,struct Block_descriptor_2和struct Block_descriptor_3是可选的。当block是全局block的时候,descriptor_2和descriptor_3是没有的。当block有捕获变量的时候,他两会存在,并会对block和捕获的变量做⼀下内存的操作。⽐如会把捕获的变量*/struct Block_layout { void *isa; volatile int32_t flags; // contains ref count int32_t reserved; BlockInvokeFunction invoke; struct Block_descriptor_1 *descriptor; // // imported variables};struct Block_descriptor_1 { uintptr_t reserved; uintptr_t size;};struct Block_descriptor_2 { // requires BLOCK_HAS_COPY_DISPOSE BlockCopyFunction copy; BlockDisposeFunction dispose;};struct Block_descriptor_3 { // requires BLOCK_HAS_SIGNATURE const char *signature; const char *layout; // contents depend on BLOCK_HAS_EXTENDED_LAYOUT};/* block 总共有6中,我们开发常⽤的有3种,_NSConcreteStackBlock、_NSConcreteMallocBlock、_NSConcreteGlobalBlock。另外的3种多在系统级别才会被使⽤到。*/void * _NSConcreteStackBlock[32] = { 0 };void * _NSConcreteMallocBlock[32] = { 0 };void * _NSConcreteAutoBlock[32] = { 0 };void * _NSConcreteFinalizingBlock[32] = { 0 };void * _NSConcreteGlobalBlock[32] = { 0 };void * _NSConcreteWeakBlockVariable[32] = { 0 };So,NSGlobalBlock、NSStackBlock、NSMallocBlock这3种⼜有啥区别呢在MRC下:NSGlobalBlock:没有访问(捕获)auto变量(局部变量)的block (数据区)NSStackBlock:访问(捕获)auto变量(局部变量)的block (栈区)NSMallocBlock: 对NSStackBlock做了⼀次copy操作后得到的block。(堆区)在ARC下:被强指针引⽤的block且引⽤了外部变量,那么会⾃动做⼀次copy操作,即把NSStackBlock上的block copy到NSMallocBlock上。即被strong,copy修饰的block且⽤了外部变量就是NSMallocBlock。判断捕获对象释放:NSStackBlock(栈上的block)会对捕获对象进⾏强引⽤。(在arc模式下,block作为函数的参数传递,此时的block是NSStackBlock)NSMallocBlock(堆上的block)会对捕获的对象进⾏引⽤,捕获的对象也会被copy到堆空间上。(如果捕获的对象是strong类型的,就会强引⽤,如果是__weak 修饰的weak类型,就会弱引⽤)。typedef void(^MyBlock)(void);@interface ViewController2 ()@property(nonatomic,copy)MyBlock myBlock;@end@implementation ViewController2- (void)viewDidLoad { [super viewDidLoad]; oundColor = [UIColor whiteColor]; int a = 10; k = ^{ // 被强指针引⽤且捕获了外部变量,会被copy到堆上,是NSMallocBlock a; // NSLog(@"%@",self); //__NSMallocBlock__ };
/*block 作为函数的参数来传递,是NSStackBlock,此时即便捕获了外部变量也不会被copy到堆上,依然是NSStackBlock,也会对捕获的外部变量强引⽤。*/ [self getMyhahahahBlock:^{ // __NSStackBlock__ a; NSLog(@"%@",self); }];}-(void)getMyhahahahBlock:(MyBlock)block{ //k = block; block(); NSLog(@"%@",block);
}block访问外部变量有⼏种⽅式呢?1. __block修饰变量(__block 只能修饰auto的局部变量,不能修饰static变量,也不能修饰全局变量)2. static修饰变量3. 全局变量那么__block 做了啥呢?__block 修饰后,底层会把捕获的局部变量包装成⼀个对象,通过捕获这个变量来修改局部变量的值。//__block修饰的变量会被封装成如下的结构体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; // 对捕获的变量copy到内存。 BlockByrefDestroyFunction byref_destroy;};struct Block_byref_3 { // requires BLOCK_BYREF_LAYOUT_EXTENDED const char *layout;};NSMutableArray *array = [NSMutableArray alloc]init];MyBlock block = ^{ [array addObject: @"hello"];
/* 这个会报错么? 被捕获的局部变量不是会被做⼀次copy操作,copy到堆上么? NSMutableArray对象被copy后,不是变成NSArray对象了么? NSArray对象能⽤addObject⽅法? */ /* 对于这个疑惑,在看了底层源码之后发现,苹果baba不是简单的调了⼀次[array copy]函数。 它其实是去堆上开辟了⼀个和array⼀样⼤的内存空间, 然后把array的内存都搬到新的array上。所以不会存在上⾯说的情况。 */ // 先开辟空间,然后做内存移动。 struct Block_byref *copy = (struct Block_byref *)malloc(src->size); memmove(copy+1, src+1, src->size - sizeof(*src));}总结来说,如果是__block修饰的变量,在block内部被修改了,这个过程中存在了3层copy操作:block被从栈copy到了堆上。__block修饰的变量被封装成⼀个对象,该对象也被copy到堆上了__block修饰的变量被封装成⼀个对象,该对象内部捕获的变量也被copy到堆上了。
发布者:admin,转转请注明出处:http://www.yc00.com/web/1689265336a226462.html
评论列表(0条)