2009-09-22 57 views
0

我有一个CoreDataHelper静态类,它由2个静态方法组成。我通过Clang运行我的项目并没有发现任何泄漏,但是通过Instruments显示泄漏,看起来像是与CoreData相关。我在Objective-C中拥有内存管理的基本知识,我相信我遵守规则。不过,我也认为我的代码更有可能出现问题,而不是Apple的CoreData堆栈中的错误。我正在运行最新的Snow Leopard,iPhone SDK 3.1,XCode 3.2。coredata内存泄漏

stack trace: 

    17 UIKit  528 Bytes -[UIApplication _run] 

    16 UIKit  64 Bytes -[UIApplication sendEvent:] 

    15 UIKit  64 Bytes -[UIApplication handleEvent:withNewEvent:] 

    14 UIKit  64 Bytes -[UIApplication _runWithURL:sourceBundleID:] 

    13 UIKit  16 Bytes -[UIApplication _performInitializationWithURL:sourceBundleID:] 

    12 helm  16 Bytes -[helmAppDelegate applicationDidFinishLaunching:] Classes/helmAppDelegate.m:113 

    11 helm  16 Bytes +[CoreDataHelper entityWithUIDexists:::] Classes/CoreDataHelper.m:50 

    10 helm  16 Bytes +[CoreDataHelper searchObjectsInContextCopy:::::] Classes/CoreDataHelper.m:39 

    9 CoreData  16 Bytes -[NSManagedObjectContext executeFetchRequest:error:] 

    8 CoreData  16 Bytes -[NSPersistentStoreCoordinator(_NSInternalMethods) executeRequest:withContext:] 

    7 CoreData  16 Bytes -[NSSQLCore executeRequest:withContext:] 

    6 CoreData  16 Bytes -[NSSQLiteConnection connect] 

    5 CoreData  16 Bytes -[NSSQLConnection createSchema] 

    4 CoreData  16 Bytes -[NSSQLConnection createTablesForEntities:] 

    3 CoreData  16 Bytes -[NSSQLConnection createTableForEntity:] 

    2 CoreData  16 Bytes -[NSSQLAdapter newCreateTableStatementForEntity:] 

    1 Foundation  16 Bytes -[NSCFString appendFormat:] 

    0 CoreFoundation  16 Bytes -[NSObject respondsToSelector:] 

的appdelegate:

BOOL b=[CoreDataHelper entityWithUIDexists:@"AddressBook" :context :[NSNumber numberWithInt:1]]; 

CoreDataHelper:

+(NSMutableArray *) searchObjectsInContextCopy: (NSString*) entityName : (NSManagedObjectContext *) managedObjectContext : (NSPredicate *) predicate : (NSString*) sortKey : (BOOL) sortAscending 
{ 
    NSLog(@"searchObjectsInContext"); 
    NSFetchRequest *request = [[NSFetchRequest alloc] init]; 
    NSEntityDescription *entity = [NSEntityDescription entityForName:entityName inManagedObjectContext:managedObjectContext]; 
    [request setEntity:entity]; 

    // If a predicate was passed, pass it to the query 
    if(predicate != nil) 
    { 
     [request setPredicate:predicate]; 
    } 

    // If a sort key was passed, use it for sorting. 
    if(sortKey != nil) 
    { 
     //NSSortDescriptor *sortDescriptor = [[NSSortDescriptor alloc] initWithKey:sortKey ascending:sortAscending selector: @selector(caseInsensitiveCompare:)]; 
     NSSortDescriptor *sortDescriptor = [[NSSortDescriptor alloc] initWithKey:sortKey ascending:sortAscending selector: @selector(caseInsensitiveCompare:)]; 
     NSArray *sortDescriptors = [[NSArray alloc] initWithObjects:sortDescriptor, nil]; 
     [request setSortDescriptors:sortDescriptors]; 
     [sortDescriptors release]; 
     [sortDescriptor release]; 
    } 

    NSError *error; 

    NSMutableArray *mutableFetchResults = [[managedObjectContext executeFetchRequest:request error:&error] mutableCopy]; 

    [request release]; 

    return mutableFetchResults; 
} 


+(BOOL) entityWithUIDexists: (NSString *) entityName : (NSManagedObjectContext *) managedObjectContext : (NSNumber *) uid { 
    BOOL b; 
    NSPredicate *predicate = [NSPredicate predicateWithFormat:@"(uid == %@)", uid]; 
    NSMutableArray *ary=[self searchObjectsInContextCopy: entityName : managedObjectContext : predicate : nil : YES]; 
    if(ary==nil) { 
     b=NO; 
    } else { 
     b=[ary count] >0 ? YES :NO; 
    } 

    [ary release]; 
    return b; 
} 

回答

1

看你的源代码,我注意到两两件事。首先,在没有排序描述符的情况下初始化一个读取请求是错误的。从SDK 3.1版本说明引用:

“ NSFetchedResultsController不再崩溃时取请求没有那种描述它仍然是无效的,而不排序描述符来初始化一个NSFetchedResultsController,而是一个适当的异常现在提出了”

因此,你应该总是用排序描述符初始化你的NSFetchedResultsController。 第二件事与你的泄漏有关。 executeFetchRequest:方法返回一个自动释放的NSArray。您正在使用mutableCopy方法,因此您正在返回已由mutableCopy保留的对象。这基本上意味着你负责释放返回的对象。再次引用mutableCopy方法文档:

“如果您使用的是托管内存(而非垃圾回收),则此方法在返回之前会保留新对象,但该方法的调用者负责释放返回的对象“。

+0

谢谢,添加排序描述符插入了16字节的内存泄漏。我相信我已经在这里手动发布获取结果: [ary release]; – deanschang 2009-09-22 21:04:42

+0

请参阅上述有关编注标记的回复。但感谢排序描述符注释。 – deanschang 2009-09-23 04:11:02

0

好的,我发现了一些有趣的东西。零排序描述符并没有引起泄漏,它仍然存在,但也许我过早地停止了泄漏检测器。这是泄漏的方法。当我注释掉杂注标记时,16个字节的泄漏不会显示在乐器中。为什么在该方法中有一个编译标记会导致16字节的泄漏?

- (NSPersistentStoreCoordinator *)persistentStoreCoordinator { 
    if (persistentStoreCoordinator != nil) { 
     return persistentStoreCoordinator; 
    } 

    NSString *databaseFilePath = [[self applicationDocumentsDirectory] stringByAppendingPathComponent: @"Locations.sqlite"]; 


    NSFileManager *fileManager = [NSFileManager defaultManager]; 

    if([fileManager fileExistsAtPath:databaseFilePath]) 
    { 
# pragma mark - flag to delete file 
     NSError *fMerror; 
     if (![fileManager removeItemAtPath:databaseFilePath error:&fMerror]) { 
      NSLog(@"persistentStoreCoordinator error %@, %@", fMerror, [fMerror userInfo]);  
     } 

    } 


    NSURL *storeUrl = [NSURL fileURLWithPath: databaseFilePath]; 

    NSError *error; 
    persistentStoreCoordinator = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel: [self managedObjectModel]]; 
    if (![persistentStoreCoordinator addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:storeUrl options:nil error:&error]) { 
     NSLog(@"persistentStoreCoordinator error %@, %@", error, [error userInfo]); }  

    return persistentStoreCoordinator; 
} 
+0

注意#和编译指示之间存在空格,当我删除该空格时,16字节的内存泄漏被插入。 16字节泄漏:#pragma mark - 标记删除文件 但不包含:#pragma mark - 标记删除文件 – deanschang 2009-09-23 04:20:42

+0

这真的很有趣(如果这确实是问题的原因) – 2012-02-05 18:09:59