在线时间:8:00-16:00
迪恩网络APP
随时随地掌握行业动态
扫描二维码
关注迪恩网络微信公众号
最近看了很多block相关的文章,都在说block怎么用,写的都很精彩。 ^int(){printf("val"); return 111;}; 这个block会被转化为 struct __block_impl { void *isa; int Flags; int Reserved; void *FuncPtr; }; struct __testBlock_block_impl_0 { struct __block_impl impl; struct __testBlock_block_desc_0* Desc; __testBlock_block_impl_0(void *fp, struct __testBlock_block_desc_0 *desc, int flags=0) { impl.isa = &_NSConcreteStackBlock; impl.Flags = flags; impl.FuncPtr = fp; Desc = desc; } }; __testBlock_block_impl_0是block结构,他的第一个属性也是一个结构__block_impl,而第一个参数也是一个isa的指针。 NSString *str = [[NSString alloc] init]; 的时候,这个NSString就在堆上挂上号了,直到release的时候,引用计数减为0,这个对象才会被干掉。 { void (^testBlock) (void) = ^{printf("看看这个block");}; testBlock(); } 的时候,在clang中会被转换为 { void (*testBlock) (void) = (void (*)())&__main_block_impl_0((void *)__main_block_func_0, &__main_block_desc_0_DATA); ((void (*)(__block_impl *))((__block_impl *)testBlock)->FuncPtr)((__block_impl *)testBlock); } 由此可见这个block是在栈上声明的,这就是说当block超过了这个“}”,这个block对象就会被回收。 block stackBlock; { int val = 10; stackBlock = ^{NSLog(@"val = %d", val);}; } stackBlock(); 转换后: block stackBlock; { int val = 10; stackBlock = (void (*)())&__main_block_impl_0((void *)__main_block_func_0, &__main_block_desc_0_DATA, val); } ((void (*)(__block_impl *))((__block_impl *)stackBlock)->FuncPtr)((__block_impl *)stackBlock); 上面的程序运行,不崩溃。 struct __main_block_impl_0 { struct __block_impl impl; struct __main_block_desc_0* Desc; int val; __main_block_impl_0(void *fp, struct __main_block_desc_0 *desc, int _val, int flags=0) : val(_val) { impl.isa = &_NSConcreteStackBlock; impl.Flags = flags; impl.FuncPtr = fp; Desc = desc; } }; 这个结构只做了构造函数,没有做析构函数,导致在对象弹栈的时候没有对对象内部变量赋值,所以飘在外面的地址都是野指针。 typedef void (^blk) (void); 之后在弄个属性 @interface ViewController () { blk tempBlock; } @end 在viewDidLoad里面加上一个按钮,并声明一个block指针付给tempBlock - (void)viewDidLoad { [superviewDidLoad]; // Do any additional setup after loading the view, typically from a nib. UIButton *btn = [UIButton buttonWithType: UIButtonTypeRoundedRect]; btn.frame = CGRectMake(100.0f, 100.0f, 100.0f, 30.0f); [btn setTitle: @"试试"forState: UIControlStateNormal]; [btn addTarget: self action: @selector(btnClick:) forControlEvents:UIControlEventTouchUpInside]; [self.viewaddSubview: btn]; __blockint val = 10; tempBlock = ^{NSLog(@"val = %d", ++val);}; } 按钮点击的事件: - (void) btnClick: (id) Sender { tempBlock(); } 当页面正常显示之后,点击按钮必然崩溃。 tempBlock = [^{NSLog(@"val = %d", ++val);} retain]; 结果依旧,可问题出在哪呢? - (void)viewDidLoad { [superviewDidLoad]; //生成按钮(略) NSLog(@"_NSConcreteStackBlock %@", [_NSConcreteStackBlock class]); __block int val = 10; blk stackBlock = ^{NSLog(@"val = %d", ++val);}; NSLog(@"stackBlock: %@", stackBlock); tempBlock = [stackBlock copy]; NSLog(@"tempBlock: %@", tempBlock); } 打印出的结果: 2013-05-29 14:21:09.969 BlockTest[2070:c07] _NSConcreteStackBlock __NSStackBlock__ 2013-05-29 14:21:09.970 BlockTest[2070:c07] stackBlock: <__NSStackBlock__: 0xbfffdb28> 2013-05-29 14:21:09.970 BlockTest[2070:c07] tempBlock: <__NSMallocBlock__: 0x756bf20> 在经过copy之后,对象的类型从__NSStackBlock__变为了__NSMallocBlock__ - (NSArray *) myTestArray { NSArray *array = [[NSArray alloc] initWithObjects: @"a", @"b", @"c", nil]; return [array autorelease]; } 同样,我们在向外传递block的时候一定也要做到,传给外面一个在堆上的,autorelease的对象。 - (blk) myTestBlock { __blockint val = 10; blk stackBlock = ^{NSLog(@"val = %d", ++val);}; return [[stackBlock copy] autorelease]; } 第一步,copy将block上从栈放到堆上,第二步,autorelease防止内存泄露。 { __blockint val = 10; __strong blk strongPointerBlock = ^{NSLog(@"val = %d", ++val);}; NSLog(@"strongPointerBlock: %@", strongPointerBlock); //1 __weak blk weakPointerBlock = ^{NSLog(@"val = %d", ++val);}; NSLog(@"weakPointerBlock: %@", weakPointerBlock); //2 NSLog(@"mallocBlock: %@", [weakPointerBlock copy]); //3 NSLog(@"test %@", ^{NSLog(@"val = %d", ++val);}); //4 } 得到的日志 2013-05-29 16:03:58.773 BlockTest[3482:c07] strongPointerBlock: <__NSMallocBlock__: 0x7625120> 2013-05-29 16:03:58.776 BlockTest[3482:c07] weakPointerBlock: <__NSStackBlock__: 0xbfffdb30> 2013-05-29 16:03:58.776 BlockTest[3482:c07] mallocBlock: <__NSMallocBlock__: 0x714ce60> 2013-05-29 16:03:58.777 BlockTest[3482:c07] test <__NSStackBlock__: 0xbfffdb18> 分析一下: - (__unsafe_unretained blk) blockTest { int val = 11; return ^{NSLog(@"val = %d", val);}; } 调用方 NSLog(@"block return from function: %@", [self blockTest]); 得到的日志: 2013-05-29 16:09:59.489 BlockTest[3597:c07] block return from function: <__NSMallocBlock__: 0x7685640> 分析一下: |
请发表评论