[英]In ARC, dealloc method calls method/block that contains weak reference to self result in weakSelf = nil
[英]Always pass weak reference of self into block in ARC?
我對Objective-C中的塊使用有點困惑。 我目前使用ARC,我的應用程序中有很多塊,目前總是指self
而不是弱引用。 這可能是導致這些障礙保留self
並防止其被解除分配的原因嗎? 問題是,我是否應該總是在一個區塊中使用self
的weak
引用?
-(void)handleNewerData:(NSArray *)arr
{
ProcessOperation *operation =
[[ProcessOperation alloc] initWithDataToProcess:arr
completion:^(NSMutableArray *rows) {
dispatch_async(dispatch_get_main_queue(), ^{
[self updateFeed:arr rows:rows];
});
}];
[dataProcessQueue addOperation:operation];
}
ProcessOperation.h
@interface ProcessOperation : NSOperation
{
NSMutableArray *dataArr;
NSMutableArray *rowHeightsArr;
void (^callback)(NSMutableArray *rows);
}
ProcessOperation.m
-(id)initWithDataToProcess:(NSArray *)data completion:(void (^)(NSMutableArray *rows))cb{
if(self =[super init]){
dataArr = [NSMutableArray arrayWithArray:data];
rowHeightsArr = [NSMutableArray new];
callback = cb;
}
return self;
}
- (void)main {
@autoreleasepool {
...
callback(rowHeightsArr);
}
}
這不僅有助於把重點放在strong
或weak
的討論的一部分。 而是專注於循環部分。
保留周期是當對象A保留對象B時發生的循環, 而對象B保留對象A.在這種情況下,如果釋放了任一對象:
因此,這兩個對象只會在程序的生命周期中閑逛,即使它們應該在一切正常工作的情況下被解除分配。
所以,我們擔心的是保留周期 ,並且沒有關於創建這些周期的塊本身。 這不是問題,例如:
[myArray enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop){
[self doSomethingWithObject:obj];
}];
該塊保留self
,但self
不保留該塊。 如果釋放了一個或另一個,則不會創建任何循環,並且所有內容都會被取消分配。
你遇到麻煩的地方是這樣的:
//In the interface:
@property (strong) void(^myBlock)(id obj, NSUInteger idx, BOOL *stop);
//In the implementation:
[self setMyBlock:^(id obj, NSUInteger idx, BOOL *stop) {
[self doSomethingWithObj:obj];
}];
現在,您的對象( self
)具有對塊的明確strong
引用。 該塊具有對self
的隱含強烈引用。 這是一個循環,現在這兩個對象都不會被正確釋放。
因為,在這樣的情況下, self
定義已經具有對塊的strong
引用,通常通過對塊使用明確弱的self
引用來解決它:
__weak MyObject *weakSelf = self;
[self setMyBlock:^(id obj, NSUInteger idx, BOOL *stop) {
[weakSelf doSomethingWithObj:obj];
}];
但這不應該是你在處理調用self
塊時遵循的默認模式 ! 這應該僅用於打破自我和塊之間的保留周期。 如果你在任何地方采用這種模式,那么你就有可能將一個塊傳遞給在取消分配self
之后執行的東西。
//SUSPICIOUS EXAMPLE:
__weak MyObject *weakSelf = self;
[[SomeOtherObject alloc] initWithCompletion:^{
//By the time this gets called, "weakSelf" might be nil because it's not retained!
[weakSelf doSomething];
}];
您不必總是使用弱引用。 如果您的塊未被保留,但已執行然后被丟棄,則您可以強烈捕獲自身,因為它不會創建保留周期。 在某些情況下,您甚至希望塊保持自身直到塊完成,因此它不會過早釋放。 但是,如果您強烈捕獲塊,並且在捕獲自身內部,則會創建一個保留周期。
我完全贊同@jemmons。
“但這不應該是你在處理調用self的塊時所遵循的默認模式!這應該僅用於打破自我和塊之間的保留周期。如果你在各處采用這種模式,你就是' d冒着將一個塊傳遞給自我被解除分配后執行的東西的風險。“
//SUSPICIOUS EXAMPLE:
__weak MyObject *weakSelf = self;
[[SomeOtherObject alloc] initWithCompletion:^{
//By the time this gets called, "weakSelf" might be nil because it's not retained!
[weakSelf doSomething];
}];
為了解決這個問題,我們可以在塊內的weakSelf上定義一個強引用。
__weak MyObject *weakSelf = self;
[[SomeOtherObject alloc] initWithCompletion:^{
MyObject *strongSelf = weakSelf;
[strongSelf doSomething];
}];
正如Leo指出的那樣,您添加到問題中的代碼不會建議強大的參考周期(也就是保留周期)。 可能導致強引用周期的一個與操作相關的問題是,如果操作未被釋放。 雖然你的代碼片段表明你沒有將你的操作定義為並發,但是如果你有,那么如果你從未發布過isFinished
,或者如果你有循環依賴關系,或者類似的東西,它就不會被釋放。 如果未釋放操作,則視圖控制器也不會被釋放。 我建議在你的操作的dealloc
方法中添加一個斷點或NSLog
,並確認它已被調用。
你說:
我理解保留周期的概念,但我不太清楚塊中會發生什么,所以這讓我有點困惑
塊發生的保留周期(強參考周期)問題就像您熟悉的保留周期問題一樣。 塊將保持對塊中出現的任何對象的強引用,並且在塊本身釋放之前不會釋放那些強引用。 因此,如果塊引用self
,或者甚至只引用self
的實例變量,那將保持對self的強引用,直到塊被釋放時才解析(或者在這種情況下,直到釋放NSOperation
子類)。
有關更多信息,請參閱“ 使用Objective-C:使用塊編程”文檔中的“ 捕獲自身時避免強引用循環”部分。
如果您的視圖控制器仍未發布,您只需確定未解析的強引用所在的位置(假設您確認NSOperation
已取消分配)。 一個常見的例子是使用重復的NSTimer
。 或者某些自定義delegate
或其他錯誤維護strong
引用的對象。 您通常可以使用Instruments來追蹤對象獲得強引用的位置,例如:
或者在Xcode 5中:
一些解釋忽略了關於保留周期的條件[如果一組對象通過一系列強關系連接,即使沒有來自組外的強引用,它們也會保持活着。]有關更多信息,請閱讀文檔
這是你如何在塊內使用self:
//調用塊
NSString *returnedText= checkIfOutsideMethodIsCalled(self);
NSString* (^checkIfOutsideMethodIsCalled)(*)=^NSString*(id obj)
{
[obj MethodNameYouWantToCall]; // this is how it will call the object
return @"Called";
};
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.