首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >电弧__block和__weak

电弧__block和__weak
EN

Stack Overflow用户
提问于 2013-07-23 14:11:18
回答 4查看 5.3K关注 0票数 8

假设我试图从一个块中访问self

代码语言:javascript
复制
[someObject successBlock:^(NSArray *result) {
    [self someSuccessMethod];
} failure:^(NSString *errorMessage, int status) {
    [self someFailureMethod];
}];

我理解这会造成一个保留周期,而且someObjectself永远不会被取消分配。

让我困惑的是使用/不使用__block关键字时实际发生了什么。我可以通过对self进行__weak引用来修复保留周期:

代码语言:javascript
复制
__weak MyClass* me = self;
[someObject successBlock:^(NSArray *result) {
    [me someSuccessMethod];
} failure:^(NSString *errorMessage, int status) {
    [me someFailureMethod];
}];

这里不需要使用__block,因为我并不试图从块中修改me。据我所知,如果不使用__block,则在块中引用me的副本。我的问题是:如果在块中引用的只是对象的一个副本,那么为什么原始代码块创建保留周期?我猜想对self的引用只是一个副本,因为我从不使用__block关键字。我是不是想错了?

EN

回答 4

Stack Overflow用户

回答已采纳

发布于 2013-07-23 15:15:11

在第一种情况下,块捕获self,即将self的副本保存为另一个强指针。这会增加指向对象的保留计数,并导致保留周期。

在第二种情况下,块捕获me,即将me的副本保存为另一个弱指针。这不会增加保留计数,因此不会导致保留周期。

(如果在块外部和内部打印me地址,您将看到地址是不同的。块有自己的指向对象的弱指针。)

如果将指向对象解除分配,则所有弱引用(包括块保存的引用)都由object运行时设置为nil

(我只希望我做得对。)

票数 7
EN

Stack Overflow用户

发布于 2013-07-23 16:04:07

当两个对象彼此存储一个强引用时,就会发生保留循环。最简单的例子是对象a存储了对对象bb的强引用,相反的1。保留循环是目标C中的一个问题,因为它们使b相信这些对象总是在使用中,即使这些对象不是从其他任何地方引用的。

让我们回顾一下一些例子。您有对象z,它分配ab,利用它们,然后对它们进行处理。如果ab首先在它们之间创建了一个保留循环,那么ab就不会被取消分配。如果你这样做了几次,你就会严重地漏掉记忆。

保留周期的另一个实际示例是,如果a分配并强烈引用一个b对象,那么您还可以存储从ba的强引用(对象图中的许多较小的对象可能需要访问它们的父对象)。

在这些情况下,最常见的解决方案是确保包含的对象只具有对其包含对象的弱引用,并确保兄弟对象不包含对彼此的强引用。

另一种解决方案(通常不那么优雅,但在某些情况下可能合适)可能是在a中有某种自定义的a方法,nils引用b。因此,当调用b时(如果b在其他地方没有被强烈引用),cleanup将被释放。这很麻烦,因为您不能从adealloc (如果有保留循环的话,就永远不会调用它),而且您必须记住在适当的时候调用cleanup

  1. 注意,保留循环也是传递性的(例如,对象a强烈引用b,后者强烈引用c,后者强烈引用a)。

所有这些都说明:块的内存管理是很难理解的。

您的第一个示例可以创建一个临时保留周期(并且只有当self对象存储对someObject的强引用时)。当块完成执行并被解除分配时,这个临时保留周期就会消失。

在执行过程中,self将存储对someObject的引用、对blocksomeObject以及对selfblock。但是,它只是暂时的,因为块不会永久地存储在任何地方(除非[someObject successBlock:failure:]实现这样做,但对于完成块来说并不频繁)。

因此,在您的第一个示例中,保留周期不是一个问题。

通常,只有当某个对象存储块而不是直接执行该块时,块中的保留循环才是一个问题。然后很容易看出self强烈引用了block,而blockself有很强的引用。请注意,从块内部访问任何ivar都会自动生成对该块中的self的强引用。

确保包含的对象不强烈引用其容器的等效方法是使用__weak SelfClass *weakSelf = self访问方法和ivars (如果您通过访问器访问ivars,就像使用属性时一样)。您的块对self的引用将是弱的(它是而不是副本,它是弱引用),这将允许self在不再被强引用时解除分配。

可以说,在所有块中始终使用weakSelf是很好的做法,无论存储还是不存储,以防万一。我不知道为什么苹果没有将此作为默认行为。这样做通常不会对块代码造成任何损害,即使实际上是不必要的。

__block很少用在指向对象的变量上,因为objects并不强制这样的对象不可变。

如果有指向对象的指针,则可以调用其方法,这些方法可以使用或不使用__block对其进行修改。__block更多(仅限?)适用于基本类型的变量(int、float等)。有关在对象指针变量中使用这里时发生的情况,请参见__block。你也可以通过苹果在块编程主题上读到更多关于块编程主题的信息。

编辑:修正了在对象指针上使用__block的错误。感谢@KevinDiTraglia的指点。

票数 4
EN

Stack Overflow用户

发布于 2014-02-16 15:29:27

您的第一个示例将不会创建一个永不终止的保留循环。有保留循环,好的,但一旦完成块,将删除从块到someObject的引用。因此,someObject将至少在区块完成之前存活。这样的临时保留周期可能是好的,也可能是坏的,这取决于您想要什么:

如果你需要你的someObject活着,至少直到它的块完成,这是可以的。但是,如果没有理由保留该对象,则应该使用“弱”引用来实现它。

例如:myObject是一个视图控制器,在这些块中从网络中获取图片。如果弹出导航控制器中的someObject,则该控制器在获取图片后将无法显示它,因此不需要保留它。无论是成功还是错误都无关紧要,用户对someObject应该获取的图片不再感兴趣。在这种情况下,弱的使用是更好的选择,但是块中的代码应该比self可能是零。

票数 3
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/17812672

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档