2011-06-25 47 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