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
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
的引用将很弱(它是不是副本,它是弱引用),这将使