coredata内存泄漏

时间:2009-09-22 00:57:30

标签: iphone objective-c

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

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;
}

2 个答案:

答案 0 :(得分:1)

查看源代码,我发现了两件事。首先,初始化没有排序描述符的获取请求是错误的。引用SDK 3.1发行说明:

“当获取请求没有排序描述符时,NSFetchedResultsController不再崩溃。初始化没有排序描述符的NSFetchedResultsController仍然无效,但现在引发了一个正确的异常”

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

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

答案 1 :(得分:0)

好的,我发现了一些有趣的东西。零排序描述符没有导致泄漏,它仍然存在,但也许我太早停止泄漏检测器。这是泄漏的方法。当我注释掉pragma标记时,16字节泄漏不会出现在Instruments中。为什么在方法中使用pragma标记会导致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;
}