Ios 弧块和弱弧

Ios 弧块和弱弧,ios,objective-c,automatic-ref-counting,Ios,Objective C,Automatic Ref Counting,假设我正试图从块内访问self: [someObject successBlock:^(NSArray *result) { [self someSuccessMethod]; } failure:^(NSString *errorMessage, int status) { [self someFailureMethod]; }]; 我知道这会产生一个保留周期,someObject和self永远不会被取消分配 让我困惑的是,使用/不使用\u块关键字实际会发生什么。我可以通过对

假设我正试图从块内访问
self

[someObject successBlock:^(NSArray *result) {
    [self someSuccessMethod];
} failure:^(NSString *errorMessage, int status) {
    [self someFailureMethod];
}];
我知道这会产生一个保留周期,
someObject
self
永远不会被取消分配

让我困惑的是,使用/不使用
\u块
关键字实际会发生什么。我可以通过对self进行
\uu弱
引用来修复保留周期:

__weak MyClass* me = self;
[someObject successBlock:^(NSArray *result) {
    [me someSuccessMethod];
} failure:^(NSString *errorMessage, int status) {
    [me someFailureMethod];
}];

我不需要在这里使用
\u块
,因为我没有试图从块内修改
me
。据我所知,如果我不使用
\u块
,块内会引用
me
的副本。我的问题是:如果块中引用的只是对象的副本,那么为什么原始代码块会创建保留循环?我猜对
self
的引用只是一个副本,因为我从来没有使用
\u块
关键字。我想得不对吗?

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

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

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

如果取消分配指向的对象,则所有弱引用(包括由 Objective-C运行时将块设置为
nil


(我只是希望我做对了。)

您可以将self作为块的参数进行路径设置,确切地说是给变量名“self”,这样可以防止块中的self保留

而你是“someObject和self永远不会被释放”:self将在释放块时被释放。块将与someObject解除分配。当SomeObject没有更多引用时,它将被释放。因此,如果您的self对象拥有someObject,那么在您不再需要它时释放它。

当两个对象存储对彼此的强引用时,就会发生一个保留周期。最简单的情况是对象
a
存储对对象
b
的强引用,而
b
则相反[1]。保留周期在Objective-C中是一个问题,因为它们使ARC相信这些对象始终在使用中,即使这些对象没有从其他任何地方引用

让我们回顾一些例子。您有一个对象
z
,它分配
a
b
,利用它们,然后处理它们。如果
a
b
首先在它们之间创建了一个保留周期,
a
b
将不会被解除分配。如果您多次这样做,您将严重泄漏内存

保留周期的另一个真实示例是,如果
a
分配并强引用
b
对象,但您也存储了从
b
a
的强引用(对象图中的许多较小对象可能需要访问其父对象)

在这些情况下,最常见的解决方案是确保包含的对象仅对其包含的对象具有弱引用,并且还确保同级对象之间不包含强引用

另一种解决方案(通常不那么优雅,但在某些情况下可能合适)可能是在
a
中使用某种自定义
cleanup
方法,使其对
b
的引用为零。因此,
b
将在调用
cleanup
时被解除分配(如果
b
在其他地方没有被强烈引用)。这很麻烦,因为您无法从
a
dealloc
执行此操作(如果存在保留周期,则不会调用它),而且您必须记住在适当的时间调用
cleanup

  • 请注意,retain循环也是可传递的(例如,对象
    a
    强烈引用
    b
    它强烈引用
    c
    它强烈引用
    a

  • 综上所述:块的内存管理很难理解

    第一个示例可以创建一个临时保留周期(并且仅当
    self
    对象存储了对
    某个对象的强引用时)。当块完成执行并被释放时,这个临时保留周期就消失了

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

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

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

    确保包含的对象不强引用其容器的等效方法是使用
    \uu弱SelfClass*weakSelf=self
    来访问方法和IVAR(如果通过访问器访问IVAR,就像使用属性时一样,效果更好)。您的块对
    self
    的引用将很弱(它是不是副本,它是弱引用),这将使