block之__block小结

demo下载

block的分类

block可分为三种
NSStackBlock:栈block
NSMallocBlock:堆block
NSGlobalBlock:全局block

1. 栈block

特点:生命周期由系统控制,函数返回即销毁
用到局部变量、成员属性\变量,且没有强指针引用的block都是栈block

a.用到局部变量,i为局部变量,block直接在NSLog中打印,没有被指针引用


- (void)viewDidLoad {
    [super viewDidLoad];
    int i = 10;
    NSLog(@"%@",^{
        NSLog(@"%d",i);
    });
}

打印结果如下:

2017-02-21 19:05:02.417 blockDemo[11626:921093] <__NSStackBlock__: 0x7fff59b31a68>

b.用到成员属性\变量(图2),name为成员属性

#import "ViewController.h"
@interface ViewController ()
@property(nonatomic,strong)NSString *name;
@end

@implementation ViewController
- (void)viewDidLoad {
    [super viewDidLoad];
      self.name = @"lily";
    NSLog(@"%@",^{
        NSLog(@"%@",self.name);
    });
}
@end

打印结果如下:

2017-02-21 19:08:07.825 blockDemo[11646:922905] <__NSStackBlock__: 0x7fff54283a68>

2. 堆block

特点:没有强指针引用即销毁,生命周期由程序员手动管理
栈block如果有强指针引用或copy修饰的成员属性引用就会被拷贝到堆中,变成堆block

a.强指针引用(图3),block被testBlock引用,testBlock就是一个block类型的强指针(ARC环境下默认就是强指针)

- (void)viewDidLoad {
    [super viewDidLoad];    
    int i = 10;
    void(^block)() = ^{
        NSLog(@"%d",i);
    };
    NSLog(@"%@",block);    
}

打印结果如下:

2017-02-21 19:11:25.929 blockDemo[11672:925232] <__NSMallocBlock__: 0x608000057730>

b.copy修饰的成员属性引用

#import "ViewController.h"

@interface ViewController ()
@property(nonatomic,copy) void(^testBlock)();
@end

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    
   int i = 10;
   self.testBlock = ^{
      NSLog(@"%d",i);
    };
   NSLog(@"%@",self.testBlock);  
}

- (void)didReceiveMemoryWarning {
    [super didReceiveMemoryWarning];
}
@end

打印结果如下:

2017-02-21 19:15:27.116 blockDemo[11699:928199] <__NSMallocBlock__: 0x6000000574f0>

3. 全局block

特点:命长,有多长?很长很长,人在塔在(应用程序在它就在)
没有用到外界变量,或者只用到全局变量、静态(static)变量的block就是全局block

a.没有用到外界变量,下图中block没有用到外界变量,所以就算用weak修饰也是全局block(举个例子而已,开发中不要用weak,用了也别说是笔者教的)

#import "ViewController.h"

@interface ViewController ()
@property(nonatomic,weak) void(^testBlock)();
@end

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    self.testBlock = ^{
    };
    NSLog(@"%@",self.testBlock);
}

打印结果如下:

2017-02-21 19:21:20.174 blockDemo[11743:932777] <__NSGlobalBlock__: 0x10eeba0a0>

b.只用到全局变量、静态(static)变量,str为全局变量,str1为静态变量,只用到其中一个也是全局block

#import "ViewController.h"

@interface ViewController ()
@end

NSString *str = @"静态变量";

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];
static NSString *str1 = @"静态变量";
    
    void(^quanjvBlock)() = ^{
        
        NSLog(@"%@,%@",str,str1);
    };
      NSLog(@"%@",quanjvBlock);
}

打印结果如下:

2017-02-21 19:27:37.323 blockDemo[11775:936994] <__NSGlobalBlock__: 0x1064f50a0>

分类总结

1.用到局部变量、成员属性 . 变量的block为栈block,生命周期系统控制,函数返回即销毁,
2.有强指针引用或copy修饰的成员属性引用的block会被复制一份到堆中成为堆block,没有强指针引用即销毁,生命周期由程序员控制
3.没有用到外界变量或只用到全局变量、静态变量的block为全局block,生命周期从创建到应用程序结束

block对外界变量的捕获

a.基本数据类型---局部变量

block会拷贝该变量的值当做常量使用,外界修改变量的值不会影响block内部,且block内部不能对其修改

block内部修改外界变量i的值直接报错,如果想要修改,可以在int i = 0前面加上关键字__block,此时i等效于全局变量或静态变量

- (void)viewDidLoad {
    [super viewDidLoad];
        int i = 10;
        void(^block)() = ^{
            NSLog(@"block内部的i值为 : %d",i);
        };
        i ++;
        NSLog(@"i = %d",i);
     block();
}

外界变量i从10变成了11,block内部打印依然是10

打印结果如下:

2017-02-21 19:47:38.682 blockDemo[11881:949181] i = 11
2017-02-21 19:47:38.683 blockDemo[11881:949181] block内部的i值为 : 10

b.基本数据类型---静态变量、全局变量、成员属性\变量

block直接访问变量地址,在block内部可以修改变量的值,并且外部变量被修改后,block内部也会跟着变


#import "ViewController.h"

@interface ViewController ()
@property(nonatomic,assign)int k;
@end
// 全局变量
int j = 10;
@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];    
// 静态变量
    static int i = 10;
    self.k = 10;  
    void(^block)() = ^{
    i ++;
    _k ++;
    j ++;
        NSLog(@"block内部的i = %d,j = %d, k = %d",i,j,_k);
    };
    i ++;
    _k ++;
    j ++;
    NSLog(@"i = %d,j = %d, k = %d",i,j,_k);
    block();   
}

block内部操作和外部操作都会影响到block里面的值
打印结果如下:

2017-02-21 20:03:58.726 blockDemo[11969:960622] i = 11,j = 11, k = 11
2017-02-21 20:03:58.727 blockDemo[11969:960622] block内部的i = 12,j = 12, k = 12

c.指针类型---局部变量

block会复制一份指针并强引用指针所指对象,且内部不能修改指针的指向
图中被注释掉的代码试图修改指针指向,所以会报错(如果想要修改,在前面加上__block),但是可以修改所指对象的值,如str从“abc”变成了“abcdef”

__block的作用:

我们都知道:Block不允许修改外部变量的值,这里所说的外部变量的值,指的是栈中指针的内存地址。__block 所起到的作用就是只要观察到该变量被 block 所持有,就将“外部变量”在栈中的内存地址放到了堆中。进而在block内部也可以修改外部变量的值 (详细介绍可以产考:http://www.jianshu.com/p/404ff9d3cd42)

- (void)viewDidLoad {
    [super viewDidLoad];
  
    NSMutableString *str = [[NSMutableString alloc]initWithString:@"abc"];
    void(^block)() = ^{
      //  str = [[NSMutableString alloc]initWithString:@"def"];
        [str appendString:@"def"];
        NSLog(@"%@",str);
    };
    block();
}

打印结果如下 :

2017-02-21 20:34:17.318 blockDemo[12084:976636] abcdef

d.指针类型---全局变量、静态变量、成员变量\属性

block不会复制指针,但是会强引用该对象,内部可修改指针指向,block会强引用成员属性\变量所属的对象,这也是为什么block内部用到self.xxx或_xxx可能会引起循环引用的原因

图中str2为成员属性,由于NSString是不可变的,所以从打印结果可以看出,在block内部修改了外界指针变量的引用,指向了新的字符串

#import "ViewController.h"

@interface ViewController ()
@property(nonatomic,strong)NSString *str1;
@end
NSString *str2 = @"静态变量";
@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];    
    static NSString *str3 = @"静态变量";
    self.str1 = @"属性";
    void(^block)() = ^{
        self.str1 = @"属性+";
        str3 = @"静态变量+";
        str2 = @"全局变量+";
 NSLog(@"self.str1 = %@,str2 = %@,str3 = %@",self.str1,str2,str3);
    };
    block();
}

打印结果如下:

2017-02-21 20:50:25.486 blockDemo[12166:986285] self.str1 = 属性+,str2 = 全局变量+,str3 = 静态变量+


最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 214,904评论 6 497
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,581评论 3 389
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 160,527评论 0 350
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,463评论 1 288
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,546评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,572评论 1 293
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,582评论 3 414
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,330评论 0 270
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,776评论 1 307
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,087评论 2 330
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,257评论 1 344
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,923评论 5 338
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,571评论 3 322
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,192评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,436评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,145评论 2 366
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,127评论 2 352

推荐阅读更多精彩内容

  • 《Objective-C高级编程》这本书就讲了三个东西:自动引用计数、block、GCD,偏向于从原理上对这些内容...
    WeiHing阅读 9,810评论 10 69
  • 前言 Blocks是C语言的扩充功能,而Apple 在OS X Snow Leopard 和 iOS 4中引入了这...
    小人不才阅读 3,762评论 0 23
  • 摘要 Blocks是C语言的扩充功能, iOS 4中引入了这个新功能“Blocks”,那么block到底是什么东西...
    CholMay阅读 1,162评论 2 10
  • 导语 在上一篇文章《iOS之轻松上手block(上)》中,笔者已经讲述了block的使用与注意事项,此文继续讲解b...
    codingZero阅读 5,835评论 34 97
  • iOS面试小贴士 ———————————————回答好下面的足够了------------------------...
    不言不爱阅读 1,972评论 0 7