2011-06-25 85 views
4

我有下面的代碼在我的iOS應用檢索文件路徑:爲什麼靜態NSString泄漏?

static const NSString * fullPathFromRelativePath(NSString *relPath) 
{ 
    // do not convert a path starting with '/' 
    if(([relPath length] > 0) && ([relPath characterAtIndex:0] == '/')) 
     return relPath; 

    NSMutableArray *imagePathComponents = [NSMutableArray arrayWithArray:[relPath pathComponents]]; 

    NSString *file = [imagePathComponents lastObject];  
    [imagePathComponents removeLastObject]; 

    NSString *imageDirectory = [NSString pathWithComponents:imagePathComponents]; 

    NSString *fullpath = [[NSBundle mainBundle] pathForResource:file 
                 ofType:NULL 
                inDirectory:imageDirectory]; 
    if (!fullpath) 
     fullpath = relPath; 

    return fullpath;  
} 

static const char * fullCPathFromRelativePath(const char *cPath) 
{ 
    NSString *relPath = [NSString stringWithCString:cPath encoding:NSUTF8StringEncoding]; 
    const NSString *path = fullPathFromRelativePath(relPath); 
    const char *c_path = [path UTF8String]; 
    return c_path; 
} 

static const char * relativeCPathForFile(const char *fileName) 
{   
    NSString *relPath = [NSString stringWithCString:fileName encoding:NSUTF8StringEncoding];   
    const NSString *path = fullPathFromRelativePath(relPath); 
    const char *c_path = [[path stringByDeletingLastPathComponent] UTF8String];  
    return c_path; 
} 

我得到了不少這一類的郵件在調試控制檯:

objc[4501]: Object 0x6e17060 of class __NSCFString autoreleased with no pool in place - just leaking - break on objc_autoreleaseNoPool() to debug 
objc[4501]: Object 0x6e12470 of class NSPathStore2 autoreleased with no pool in place - just leaking - break on objc_autoreleaseNoPool() to debug 
objc[4501]: Object 0x6e12580 of class __NSCFData autoreleased with no pool in place - just leaking - break on objc_autoreleaseNoPool() to debug 

什麼問題與代碼? (我甚至使用iOS 5與「自動」保留/釋放等)

乾杯。

回答

11

當您在堆棧中沒有任何發佈池的線程上自動釋放對象時,會顯示此消息。默認情況下,主線程上總是有一個自動釋放池。它在UIApplicationMain()函數中創建和管理,通常由您的應用程序的main()函數調用。但是,您創建的其他線程(使用performSelectorInBackground:NSThread)沒有適當的自動釋放池,除非您特別在其中放置一個線程,因此該後臺線程上的任何自動釋放對象都沒有池以便稍後釋放它們,並且只會泄漏。

如果你正在踢東西到後臺線程,你應該做的第一件事是創建一個autorelease池。在ARC下,使用新的@autoreleasepool構造來實現。

+0

嘿那裏,這個答案是正確的。我沒有通過任何cocoa API創建更多的線程,但是我有一些新的線程由較低級別的C函數創建,這是造成這個問題的原因。我圍繞@autoreleasepool封裝了第一個方法,問題得到解決。 還在圍繞着ARC環顧我的頭:) – Goles

0

我不認爲這是真正的泄漏。 Apple已經多次討論過這個問題,在模擬器上它是模擬器庫處理NSAutoReleasePool的一個已知的僞錯誤,但是不足以保證修復,因爲你的mac的內存比設備多得多。在WWDC上他們提到NSZombie並沒有正確處理autorelease,但我記不起什麼會話。除非你注意到Instruments中的這些對象泄漏,否則你不應該擔心它。如果您發現泄漏使用儀器,請提供bugreport

不要在您的方法周圍創建一個Autorelease Pool,因爲它看起來可能會泄漏。在ARC上無法正常工作,除非您修改了應用程序的main()函數,否則您的autorelease池將的所有內容全部包裝爲。創建額外的自動釋放池而不分析數據,表明在調用該方法後存在嚴重的內存壓力,這實際上會使應用程序性能變差。

+0

如果您在後臺線程上有代碼,則您沒有包含所有內容的autorelease池; autorelease池UIKit爲您創建的僅適用於主線程。 –

+0

這是真的,並且可能是Apple推動開發者使用block&GCD的主要原因之一。但OP沒有提到在後臺線程上工作...... – RyanR

+1

不,OP沒有提到後臺線程,但是這個錯誤幾乎全部發生在後臺線程上,除非你修改了main()來不調用UIApplicationMain(),這是不太可能的。 –

0

如果您在main.m文件中刪除了NSAutoreleasePool調用,或者此代碼正在獨立線程中執行,則會發生這種情況。 由於無法將NSAutoreleasePool與ARC一起使用,因此必須將線程代碼置於@autoreleasepool塊中

+0

,OP明確聲明這是NSAutoreleasePool [不能在ARC項目中使用](http://developer.apple.com/library/prerelease/ios/#documentation/General/Conceptual/ARCProgrammingGuide/Introduction.html)。它不會編譯。 – RyanR

+0

無法使用NSAutoreleasePool對象。 ARC提供了@autoreleasepool塊。這些優勢比NSAutoreleasePool更高效。 – edo42

+0

從你給我的頁面複製 – edo42

1

您是否曾嘗試在非ARC應用程序中運行相同的代碼?通過這樣做,您可以確認它是否是ARC問題或框架中的實際錯誤。 ARC還不成熟,蘋果多次表示它還沒有完成,肯定有缺陷。

如果您擔心正在創建的明顯的autorelease對象的數量,請圍繞相關代碼使用@autoreleasepool {...}構造。它相當於一個NSAutoreleasePool的more efficient,無論如何你都不能在ARC代碼中創建它。

+0

謝謝!,還在習慣ARC :)。圍繞@autoreleasepool在第一個方法中包裝代碼解決了問題。 (這是@autoreleasepool,而不是@autorelease) – Goles