0

我已經閱讀了幾個處理類似問題的線程,但我無法弄清楚我過度釋放了什麼。從一個Player對象的詳細視圖控制器,我推一個UITableViewController以選擇播放器位置的對象:第二次保存NSManagedObjectContext時出錯(解除分配的insance)

- (void)selectLocations 
{ 
    LocationSelectionController *vc = [[LocationSelectionController alloc] initWithStyle:UITableViewStyleGrouped]; 
    vc.player = player; 
    [self.navigationController pushViewController:vc animated:YES]; 
    [vc release]; 
} 

這裏看看LocationSelectionController的一些細節:

- (void)saveContext { 
    NSManagedObjectContext *context = [player managedObjectContext]; 
    if ([context hasChanges]) { 
    NSError *error = nil; 
     if (![context save:&error]) { //*** ERROR HERE *** 
      // show alert 
     } 
    } 
} 

- (void)viewDidLoad { 
    [super viewDidLoad]; 
    // .... 

    NSError *error = nil; 
    if (![[self fetchedResultsController] performFetch:&error]) { 
     // show alert 
    } 
} 

- (NSFetchedResultsController *)fetchedResultsController { 
    if (_fetchedResultsController != nil) { 
     return _fetchedResultsController; 
    } 
    NSManagedObjectContext *context = [player managedObjectContext]; 
    NSFetchRequest *request = [[NSFetchRequest alloc] init]; 
    NSEntityDescription *entity = [NSEntityDescription entityForName:@"Location" inManagedObjectContext:context]; 
    [request setEntity:entity]; 

    NSSortDescriptor *sortDescriptor = [[NSSortDescriptor alloc] initWithKey:@"name" ascending:YES selector:@selector(caseInsensitiveCompare:)]; 
    NSArray *sortDescriptors = [NSArray arrayWithObjects:sortDescriptor, nil]; 
    [request setSortDescriptors:sortDescriptors]; 

    NSFetchedResultsController *aFRC = [[NSFetchedResultsController alloc] initWithFetchRequest:request managedObjectContext:context sectionNameKeyPath:nil cacheName:nil]; 
    aFRC.delegate = self; 
    self.fetchedResultsController = aFRC; 

    [request release]; 
    [sortDescriptor release]; 

    return _fetchedResultsController; 
} 

- (void)viewDidUnload { 
    [super viewDidUnload]; 
    self.fetchedResultsController = nil; 
} 


- (void)dealloc { 
    self.fetchedResultsController = nil; 
    [_fetchedResultsController release]; 
    [player release]; 
    [super dealloc]; 
} 

的功能第一次導航到LocationSelectionController時總是非常完美。我可以與Location對象進行交互,完全沒有問題。當我彈出視圖並返回到Player對象的詳細視圖時,再次有完美的功能。只有當我再次推送LocationSelectionController(即使它來自不同的Player對象),纔會嘗試保存上下文時發生崩潰。

*** -[LocationSelectionController controllerWillChangeContent:]: message sent to deallocated instance 0x7026920 

我一直在使用的儀器與NSZombie發現問題試過了,它指向我LocationSelectionController的一個實例。 Instruments Screen

回答

1

你對NSFetchedResultsController的處理是搞砸了。首先,考慮下面的代碼:

NSFetchedResultsController *aFRC = [[NSFetchedResultsController alloc] initWithFetchRequest:request managedObjectContext:context sectionNameKeyPath:nil cacheName:nil]; 
aFRC.delegate = self; 
self.fetchedResultsController = aFRC; 

如果您fetchedResultsController屬性聲明assign,該代碼是或多或少正確的(儘管隨後的語義是錯誤的)。如果該房產被宣佈爲retain,則此處泄漏對aFRC的引用。

但無論如何,您的釋放是錯誤的。在dealloc中,你有這樣的:

self.fetchedResultsController = nil; 
[_fetchedResultsController release]; 

第一行設置屬性(這大概是_fetchedResultsController伊娃)爲零,所以第二行不能釋放對象。如果財產被宣佈爲retain,我想這是一個嘗試清理上面提到的泄漏;如果它被聲明爲assign,這是上述錯誤語義的證據。即使這個工作「正確」,在viewDidUnload版本沒有這個額外的版本,所以事情是仍然錯誤。

無論哪種方式,泄漏的引用離開NSFetchedResultsController活着。最終它發現一個變化,它試圖發送給它的代表。而這當然是失敗的,因爲代表早已被釋放。


機會很好,您從來不需要從該類的實現外部分配fetchedResultsController。你真正應該做的則是這樣的:

酒店fetchedResultsController應該聲明爲:

@property (retain, readonly) NSFetchedResultsController *fetchedResultsController; 

您現有的fetchedResultsController是好的,但它應該分配_fetchedResultsController伊娃直接,而不是試圖分配self.fetchedResultsController

隨後的dealloc和viewDidUnload方法應該每個發行對象是這樣的:

[_fetchedResultsController release]; 
_fetchedResultsController = nil; 

您還可以設置_fetchedResultsController.delegate零釋放它,要格外肯定之前,但文檔並不表示這是就像它爲其他一些班級所做的那樣。

+0

你是我的英雄。謝謝你的回覆! – 2011-04-09 20:22:45

+0

親愛的Anomie,我的應用程序出現類似的問題。你可以在這裏檢查我的代碼,看看你是否注意到了什麼?謝謝! http://stackoverflow.com/questions/5815549/getting-an-nsinvalidarguementexception-error – 2011-04-28 09:11:52

0

我有一個類似的問題,結果不同。

在我的情況下,我有一些KVO觀察者在控制器中沒有相應的removeObserver:forKeyPath:dealloc中的調用。

相關問題