好吧,我是一名經驗豐富的C++開發人員。我正在嘗試構建一個相當可觀的Cocoa應用程序時即時學習Objective-C。在爲這個項目做準備時,我已經用Cocoa做了一些更簡單的應用程序,並且我認爲我可以很好地處理大多數的概念。分析器抱怨多線程可可應用程序中可能的資源泄漏
的內存管理模式還是有點含糊,我可是讓我建立一個與內存分析,以幫助我找到問題向右走,並說實話它一直真棒,卻更多地幫助我瞭解的Objective-C內存管理的任何文檔。
所以這是我的問題。
我有兩個線程使用performSelector:onThread:withObject:waitUntilDone:
方法相互通信。它們通過傳入的方法傳遞給對象,方法參數爲withObject:
。
樣本代碼如下:
- (BOOL)postMessage:(id <MessageTarget>)sender messageId:(NSInteger)msgId messageData:(void*)data
{
// message is allocated and retained here. retain count will be +2
Message* message = [[[Message alloc] initWithSender:sender messageId:msgId messageData:data] retain];
if(message)
{
// message will be released in other thread.
[self performSelectorOnMainThread:@selector(messageHandler:) withObject:message waitUntilDone:NO];
// message is released here and retain count will be +1 or 0 depending on thread ordering
[message release];
return YES;
}
return NO;
}
- (BOOL)sendMessage:(id <MessageTarget>)sender messageId:(NSInteger)msgId messageData:(void*)data messageResult:(void**)result
{
// message is allocated and retained here. retain count will be +2
Message* message = [[[Message alloc] initWithSender:sender messageId:msgId messageData:data] retain];
if(message)
{
// message will be released in other thread. retain count will be +1 on return
[self performSelectorOnMainThread:@selector(messageHandler:) withObject:message waitUntilDone:YES];
if(result)
*result = [message result];
// message is released here and retain count will be 0 triggering deallocation
[message release];
return YES;
}
return NO;
}
- (void)messageHandler:(Message*)message
{
// message will have a retain count of +1 or +2 in here based on thread execution order
if(message)
{
switch ([message messageId])
{
case
...
break;
default:
...
break;
}
// message is released here bringing retain count to +1 or 0 depending on thread execution ordering
[message release];
}
}
分析器抱怨在postMessage:
和sendMessage:
分配的Message
對象的可能的泄漏,但該對象在messageHandler:
釋放。代碼運行正常,不會泄漏,我懷疑分析器根本無法看到Message
對象正在被釋放到另一個線程中。
現在,如果你想知道爲什麼我做的第二件在後保留/發送方法,而不是在messageHandler:
方法,這是因爲postMessage:
方法,就是要在後方法異步和[message release]
之前可以得到執行messageHandler:
中的[message retain]
會使我失去一個無效的對象。如果我在sendMessage:
方法的情況下這樣做,它會工作得很好,因爲它是同步的。
那麼有沒有更好的方式來做到這一點,滿足記憶分析儀?或者,也許有一種方法可以給內存分析器提示該對象實際上正在釋放?
更新:
托裏下面提供的答案,但我想澄清什麼,我必須做什麼,從他建議不同。
他建議我messageHandler:
方法中的屬性如下
- (void)messageHandler:(Message*) __attribute__((ns_consumed)) message;
,因爲對象被傳遞到performSelector:
和分析器沒有看到它沿傳遞到messageHandler:
由於performSelector:
調用由Cocoa定義,而不是由我定義,因此我無法將該屬性添加到它。
解決這個問題的辦法是調用換到performSelector:
如下:
- (void)myPerformSelector:(SEL)sel onThread:(NSThread*)thread withObject:(id) __attribute__((ns_consumed)) message waitUntilDone:(BOOL)wait;
{
[self performSelector:sel onThread:thread withObject:message waitUntilDone:wait];
}
然後就可以調用包裝函數,分析儀將看到屬性,而不是抱怨不平衡保留/釋放對。 最後,我不喜歡額外的間接方法來擺脫警告,所以我使用了預處理器,正如我在下面的評論中所解釋的。但是我可以看到使用這種方法可能有用的情況。
我發現我可以用'的#ifndef __clang_analyzer__'包分配代碼抑制警告。這確實擺脫了警告,但我認爲壓制警告是一種破解,因此是最後的手段。 – 2012-07-07 23:37:18