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).

 

posted @ 2016-09-13 13:36  oneSong  阅读(143)  评论(0编辑  收藏