block
不使用__block修饰:
int num = 1; self.myBlock = ^(){ NSLog(@"block num == %d",num); }; num = 2; self.myBlock(); NSLog(@"last num == %d",num); // 输入结果: // 2016-09-13 13:13:15.362 block2[7543:562614] block num == 1 // 2016-09-13 13:13:15.363 block2[7543:562614] last num == 2
num 使用__block修饰后:
__block int num = 1; self.myBlock = ^(){ NSLog(@"block num == %d",num); }; num = 2; self.myBlock(); NSLog(@"last num == %d",num); // 输出结果: // 2016-09-13 13:14:20.964 block2[7574:570584] block num == 2 // 2016-09-13 13:14:20.964 block2[7574:570584] last num == 2
如果不用__block修饰变量,在block内强行修改变量会报错:
增加__block后,可以在block内部修改num:
__block int num = 1; self.myBlock = ^(){ num = 3; NSLog(@"block num == %d",num); }; num = 2; self.myBlock(); NSLog(@"last num == %d",num); // 输出结果: // 2016-09-13 13:16:44.961 block2[7632:585368] block num == 3 // 2016-09-13 13:16:44.962 block2[7632:585368] last num == 3
block调用完后再修改num:
__block int num = 1; self.myBlock = ^(){ num = 3; NSLog(@"block num == %d",num); }; self.myBlock(); num = 2; NSLog(@"last num == %d",num); // 输出结果: // 2016-09-13 13:18:38.332 block2[7681:599563] block num == 3 // 2016-09-13 13:18:38.333 block2[7681:599563] last num == 2
block对对象类型的使用和对基本数据类型的使用一样:
不用__block修饰:
NSString *str = @"1"; self.myBlock = ^(){ NSLog(@"block str == %@",str); }; str = @"2"; self.myBlock(); NSLog(@"last str == %@",str); // 输出结果: // 2016-09-13 13:23:03.091 block2[7815:628689] block str == 1 // 2016-09-13 13:23:03.092 block2[7815:628689] last str == 2
使用__block修饰:
__block NSString *str = @"1"; self.myBlock = ^(){ NSLog(@"block str == %@",str); }; str = @"2"; self.myBlock(); NSLog(@"last str == %@",str); // 输出结果: // 2016-09-13 13:25:17.199 block2[7867:638529] block str == 2 // 2016-09-13 13:25:17.199 block2[7867:638529] last str == 2
block内部修改对象:
__block NSString *str = @"1"; self.myBlock = ^(){ str = @"3"; NSLog(@"block str == %@",str); }; str = @"2"; self.myBlock(); NSLog(@"last str == %@",str); // 输出结果: // 2016-09-13 13:27:49.440 block2[7937:651966] block str == 3 // 2016-09-13 13:27:49.441 block2[7937:651966] last str == 3
block调用完后再修改对象:
__block NSString *str = @"1"; self.myBlock = ^(){ str = @"3"; NSLog(@"block str == %@",str); }; self.myBlock(); str = @"2"; NSLog(@"last str == %@",str); // 输出结果: // 2016-09-13 13:29:03.705 block2[7973:660957] block str == 3 // 2016-09-13 13:29:03.705 block2[7973:660957] last str == 2
总结:
__block的使用:
block对基本数据类型和对象类型的使用注意是一样的。即:
无论是基本数据类型还是对象类型,如果想在block内部改变外面变量的值,必须用__block修饰;如果外面的值改变也要影响block内部值,也必须用__block修饰。(与block外面的变量的值保持同步)
即如果想内部改变影响外部或者外部改变影响内部,那么变量必须用__block修饰
如果不加__block修饰,那么block会捕获变量的值,在之后不受外面变量的改变而改变;并且也不能在block内部修改变量的值
如果想在block内部修改变量的值,必须用__block修饰
block循环引用:
伴随着block能够捕获变量的能力的一个问题就是, 循环引用, 在ARC中, 只要不是用到纯C语言的库,管理内存的工作都不需要我们完成, 但是循环引用却是我们需要解决的, 最常见的就是当block捕获的变量是一个对象的属性(方法)的时候, 也就是会捕获到self, 那么这个时候就可能会造成循环引用(block属性应该被标记为copy), 解决方法也很简单, 使用一个对self弱引用的指针即可, 这个写法就很多了, 笔者习惯的写法是: __weak typeof(self) weakSelf = self;
, 那么在block中使用weakSelf
替代self
调用相关的属性或者方法, 就不会造成循环引用
weakSelf和strongSelf:
使用weakSelf能够解决block捕获self造成的循环引用的内存泄漏问题, 但是带来的另一个问题就是, 特别是在多线程中,可能在block中代码正在执行
的时候, self被销毁了, 因为使用weakSelf捕获到的是self的弱引用, 那么后续的代码就不能够继续执行了, 这个时候为了保证在这个block中self即使被销毁block里面的代码也能正常执行, 我们需要的另一个操作就是, 将weakSelf强引用一次, 让他的引用计数加1, 就能处理这个问题, 就是Apple在wwdc中提到的weak-strong-dance
, 笔者习惯的书写方式是: __strong typeof(self) strongSelf = weakSelf;
,,, 当然这个必须要明白的是, 这个block里面的strongSelf能够保证里面代码执行完毕的前提是程序能够执行到block, 如果在执行block之前self已经被销毁了, 那么这个block肯定是不会被调用的(block的引用计数已经为0).