美文网首页
深入 Block 的内存问题

深入 Block 的内存问题

作者: cbd0bfba9942 | 来源:发表于2016-05-19 17:47 被阅读180次

一些关键点:

```

block 是在栈上创建的

block 可以复制到堆上

Block会捕获栈上的变量(或指针),将其复制为自己私有的const(变量)。

(如果在Block中修改Block块外的)栈上的变量和指针,那么这些变量和指针必须用__block关键字申明(译者注:否则就会跟上面的情况一样只是捕获他们的瞬时值)。

```

如果 block 没有在其他地方被保持,那么它会随着栈生存并且当栈帧(stack frame)返回的时候消失。仅存在于栈上时,block对对象访问的内存管理和生命周期没有任何影响。

如果 block 需要在栈帧返回的时候存在,它们需要明确地被复制到堆上,这样,block 会像其他 Cocoa 对象一样增加引用计数。当它们被复制的时候,它会带着它们的捕获作用域一起,retain 他们所有引用的对象。

如果一个 block引用了一个栈变量或指针,那么这个block初始化的时候会拥有这个变量或指针的const副本,所以(被捕获之后再在栈中改变这个变量或指针的值)是不起作用的。(译者注:所以这时候我们在block中对这种变量进行赋值会编译报错:Variable is not assignable(missing __block type specifier),因为他们是副本而且是const的.具体见下面的例程)。

当一个 block 被复制后,__block 声明的栈变量的引用被复制到了堆里,复制完成之后,无论是栈上的block还是刚刚产生在堆上的block(栈上block的副本)都会引用该变量在堆上的副本。

(下面代码是译者加的)

```

CGFloat blockInt = 10;

void (^playblock)(void) = ^{

NSLog(@"blockInt = %zd", blockInt);

};

blockInt ++;

playblock();

...

//结果为:blockInt = 10

```

```

用 LLDB 来展示 block 是这样子的:

![这里写图片描述](http://img.blog.csdn.net/20160519181047277)

最重要的事情是 __block 声明的变量和指针在 block 里面是作为显示操作真实值/对象的结构来对待的。

block 在 Objective-C 的 runtime(运行时) 里面被当作一等公民对待:他们有一个 isa 指针,一个类也是用 isa 指针在Objective-C 运行时来访问方法和存储数据的。在非 ARC 环境肯定会把它搞得很糟糕,并且悬挂指针会导致 crash。__block 仅仅对 block 内的变量起作用,它只是简单地告诉 block:

嗨,这个指针或者原始的类型依赖它们在的栈。请用一个栈上的新变量来引用它。我是说,请对它进行双重解引用,不要 retain 它。 谢谢,哥们。

如果在定义之后但是 block 没有被调用前,对象被释放了,那么 block 的执行会导致 crash。 __block 变量不会在 block 中被持有,最后... 指针、引用、解引用以及引用计数变得一团糟。

self 的循环引用

当使用代码块和异步分发的时候,要注意避免引用循环。 总是使用 weak 来引用对象,避免引用循环。(译者注:这里更为优雅的方式是采用影子变量@weakify/@strongify 这里有更为详细的说明) 此外,把持有 block 的属性设置为 nil (比如 self.completionBlock = nil) 是一个好的实践。它会打破 block 捕获的作用域带来的引用循环。

例子:

```

__weak __typeof(self) weakSelf = self;

[self executeBlock:^(NSData *data, NSError *error) {

[weakSelf doSomethingWithData:data];

}];

```

不要这样:

```

[self executeBlock:^(NSData *data, NSError *error) {

[self doSomethingWithData:data];

}];

```

多个语句的例子:

```

__weak __typeof(self)weakSelf = self;

[self executeBlock:^(NSData *data, NSError *error) {

__strong __typeof(weakSelf) strongSelf = weakSelf;

if (strongSelf) {

[strongSelf doSomethingWithData:data];

[strongSelf doSomethingWithData:data];

}

}];

```

不要这样:

```

__weak __typeof(self)weakSelf = self;

[self executeBlock:^(NSData *data, NSError *error) {

[weakSelf doSomethingWithData:data];

[weakSelf doSomethingWithData:data];

}];

```

你应该把这两行代码作为 snippet 加到 Xcode 里面并且总是这样使用它们。

```

__weak __typeof(self)weakSelf = self;

__strong __typeof(weakSelf)strongSelf = weakSelf;

```

相关文章

  • 深入 Block 的内存问题

    一些关键点: ``` block 是在栈上创建的 block 可以复制到堆上 Block会捕获栈上的变量(或指针)...

  • Block探索

    Block内存关系Block经典问题循环引用&解决Block底层分析Block底层HooK 程序占用内存分类 栈区...

  • 深入Block内存管理

    Block类型 根据Block在内存中的位置,系统把Block分为3类:NSGlobalBlock,NSStack...

  • iOS当用weak来修饰block时,会发生什么?

    之前验证过copy修饰的block,编译器做了什么。详见文章通过__block的作用深入研究block。与内存有关...

  • Block内存问题

    这种写法会报错,因为在block中使用的a相当于是一个常亮10,在runtime语句中是将a作为一个常亮在传递就是...

  • OC语法 Block

    问题: Block的原理、本质是什么? Block的分类? Block的捕获机制? Blcok内部的内存管理? _...

  • Block经典问题循环引用&解决

    Block内存关系Block经典问题循环引用&解决Block底层分析Block底层HooK 1.循环引用怎么产生的...

  • [iOS面试]第5章 Block相关面试问题

    本文主讲Block相关面试问题,包括Block介绍、截获变量、__block修饰符、Block的内存管理、Bloc...

  • Block相关面试问题

    本文主讲Block相关面试问题,包括Block介绍、截获变量、__block修饰符、Block的内存管理、Bloc...

  • Block底层分析

    Block内存关系Block经典问题循环引用&解决Block底层分析Block底层HooK 1. 研究工具:cla...

网友评论

      本文标题:深入 Block 的内存问题

      本文链接:https://www.haomeiwen.com/subject/azegrttx.html