由三个面试题引起的block总结

block.jpg

iOS开发中,block的使用还是挺频繁的,不管是自定义还是系统提供的很多block函数。但是抽丝剥茧的事还是发生在面试中,面试的时候block被提问的概率还是挺高的。
   以下根据面试题做出对block部分知识点的讲解,仅代表个人看法,如果有错误,请指出。
看题之前,先了解一下block类型:

分NSConcreteGlobalBlock
NSConcreteStackBlock
NSConcreteMallocBlock分别在全局变量区,栈区,堆区。

_NSConcreteGlobalBlock类型的block要么是空block,要么是不访问任何外部变量的block。它既不在栈中,也不在堆中,我理解为它可能在内存的全局区。(配置在全局变量上的Block,从变量作用域外也可以通过指针安全地使用)
举例:

    void(^ blockA)() = ^{
        NSLog(@"just a block");
    };

_NSConcreteStackBlock类型的block有闭包行为,也就是有访问外部变量,并且该block只且只有有一次执行,因为栈中的空间是可重复使用的,所以当栈中的block执行一次之后就被清除出栈了,所以无法多次使用。
举例:

下边这个例子,如果在ARC下创建,blockC会创建在堆上,如果在MRC 环境下创建会创建在栈上。
  int value = 10;
    void(^ blockC)() = ^{
        NSLog(@"just a block === %d", value);
    };

_NSConcreteMallocBlock类型的block有闭包行为,并且该block需要被多次执行。当需要多次执行时,就会把该block从栈中复制到堆中,供以多次执行。
举例:

void addBlockToArray(NSMutableArray *array) {
    char b = 'B';
    [array addObject:^{
            printf("%c\n", b);
    }];
}
void exampleB() {
    NSMutableArray *array = [NSMutableArray array];
    addBlockToArray(array);
    void (^block)() = [array objectAtIndex:0];
    block();
}
addBlockToArray中的block还在栈区,exampleB中的block被复制到了堆区变成了NSConcreteMallocBlock。

提问的第一个问题如下:

1,下面代码在按钮点击后,在ARC下会发生什么,MRC下呢?为什么?

@property(nonatomic, assign) void(^block)();

- (void)viewDidLoad {
    [superviewDidLoad];
    int value = 10;
    void(^blockC)() = ^{
        NSLog(@"just a block === %d", value);
    };

    NSLog(@"%@", blockC);
    _block = blockC;

}

- (IBAction)action:(id)sender {
    NSLog(@"%@", _block);
}

经测试,在ARC环境下是不会崩溃的,在MRC环境下因为访问已经释放的对象,程序崩溃。个人给出的解释是,在ARC环境下,创建的blockC ,blockC是在堆区,MRC环境下blockC是在栈区,栈区在函数返回以后就销毁,再次访问的时候就会引起访问已经销毁的对象。
注:此处之前搜到的答案是这样的:@property(nonatomic, assign) void(^block)(); 在ARC环境下,不管用assign,copy还是strong来修饰block都会被copy到堆区,所以block不会因为函数的返回而销毁。在MRC环境下必须用copy然后调用点语法赋值(self.block = blockC),block 就会从栈区copy到堆区。
但是实际测试结果如下:

   int a =0;
    self.block=^{
        NSLog(@"aaa%d",a);
    };
    
    NSLog(@"aaa");

结果显示


显示在栈区.png

  所以个人认为,上边block在ARC环境下没有销毁,是因为blockC在堆区,而不是说ARC环境下assign修饰的block被copy到了堆区。
因此不管在MRC 还是ARC 定义成属性的block要用copy防止过早销毁。

2,在ARC环境下这段代码为什么不会崩溃?

@property(nonatomic, weak) void(^block)();

- (void)viewDidLoad {
    [super viewDidLoad];

    void(^ __weak blockA)() = ^{
        NSLog(@"just a block");
    };

    _block = blockA;

}

- (IBAction)action:(id)sender {
    _block();
}

经过测试blockA是在全局变量区,类型是NSConcreteGlobalBlock前边注意到(配置在全局变量上的Block,从变量作用域外也可以通过指针安全地使用)。

在全局变量区.png

在MRC环境直接写报错,需要将 _weak做处理,不做深究。
注:在第一题中我们发现,直接创建的block是在堆区的,但是经过__weak修饰后会放在栈区。

下面代码中为什么可以直接用self?
[UIView animateWithDuration:1 animations:^{
    self.view.backgroundColor = [UIColor yellowColor];
}];

下面这段代码可以用self吗?为什么?
- (void)doSomething {
    [BlockClass doSomethingUseBlock:^{
        NSLog(@"%@", self);
    }];
}

关于第一个问题,我们会发现,在很多情况下,block中使用self不会引起循环引用问题,这首先,我们要搞明白什么是循环引用,就是当前类持有强引用这个block,然后在block中又强引用了当前类,彼此等待都不能销毁。但是UIView是一个类,当前控制器不可能强引用一个类,所以当前控制器没有强引用这个block,循环不成立。(第二个问题也就回答了)
此处拓展,在AFN中也是在block中使用self,他是进行了特殊处理,原理可以自己去搜一下。系统GCD是在结束的时候将对象都进行了释放。

以下补充知识点:

补充1. 关于block中变量修改引起的思考。
我们知道block中是不能直接修改外部变量的,必须经过_block修饰。原因是:block不允许修改的是栈中指针的内存地址,__block的作用是将栈中的地址放到堆中,这样就可以修改了。
补充2. 关于block中使用weak和strong修饰词
首先我们知道,为了防止循环引用,我们会使用weak来修饰self,防止产生强引用,但是在很多框架中我们会发现,block中还会有strong修饰词,这是防止block还在执行的时候,别的地方把self给释放了。找一个别人写好的例子

 第一步:我们自定义一个类,在该类dealloc方法中加一行打印语句;

@interface SampleObject :NSObject

@end

@implementation SampleObject

- (void)dealloc{

NSLog(@"dealloc %@",[self class]); 

}

@end

第二步:实例化该类,并在block中调用它;(没有加strong修饰符,三秒后释放该对象)

SampleObject* sample = [[SampleObject alloc]init];

self->sample= sample;

__weakSampleObject* weaksample = self->sample;

dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT,0), ^{

NSIntegercount =0;

//__strong SampleObject* strongsample = weaksample;

while(count<10) {

count++;

NSLog(@"aaa %@",weaksample);

sleep(1);

}

});

dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(3*NSEC_PER_SEC)),dispatch_get_main_queue(), ^{

self->sample=nil;

});

打印结果如下(没有用strong修饰符的打印结果如下):

输出.png

结论是:如果仅仅使用__weak去修饰变量,当别处把变量释放后,block中该变量也会被释放掉。
那么好,我们在把第二步中的方法修改一下,加上strong修饰符:

dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT,0), ^{

__strongSampleObject* strongsample = weaksample;

NSIntegercount =0;

while(count<10) {

count++;

NSLog(@"aaa %@",strongsample);

sleep(1);

}

});

打印结果如下:


加strong输出.png

结论是当加上修饰符strong时,当别处把变量释放掉,但调用该变量的block如果仍然没有执行结束,那么系统就会等待block执行完成后再释放,对该变量在block中的使用起到了保护作用。当block执行结束后会自动释放掉。

继续整理补充,,,,

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

推荐阅读更多精彩内容

  • 《Objective-C高级编程》这本书就讲了三个东西:自动引用计数、block、GCD,偏向于从原理上对这些内容...
    WeiHing阅读 9,813评论 10 69
  • 前言 Blocks是C语言的扩充功能,而Apple 在OS X Snow Leopard 和 iOS 4中引入了这...
    小人不才阅读 3,768评论 0 23
  • Block 梳理与疑问 时隔一年,再次读 《Objective-C 高级编程》,看到 block 一章,这一次从头...
    DeerRun阅读 638评论 0 2
  • 把网上的一些结合自己面试时遇到的面试题总结了一下,以后有新的还会再加进来。 1. OC 的理解与特性 OC 作为一...
    AlaricMurray阅读 2,564评论 0 20
  • 一、HTML、XML、XHTML 有什么区别 HTML,全名为超文本标记语言(Hyper Text Marku...
    select_yang阅读 178评论 0 0