2009-09-22 53 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