簡體   English   中英

核心數據應用因“ controllerWillChangeContent:無法識別的選擇器發送到實例”而崩潰

[英]Core Data app crashing with “controllerWillChangeContent : unrecognized selector sent to instance”

我有一個具有2個視圖的核心數據應用程序。 第一個視圖列出“房間”,第二個視圖列出房間中的“場景”。 “房間”頁面上有一個編輯NavItem按鈕,按下該按鈕將啟用添加NavItem按鈕。 您可以從此處刪除和添加房間。 添加的房間僅在表中以默認的“新房間”名稱顯示。 第二個視圖是所選房間中的場景列表。 同樣的操作,您可以刪除和添加場景,添加的場景僅在表中顯示為“新場景”。 真的沒什么特別的。

我在兩個視圖控制器中都使用了FetchedResultsController ,其中的Scenes具有一個NSPredicate ,僅返回所選房間中的場景。 我還使用controllerWillChangeContentcontrollerDidChangeContent等代理方法來更新表視圖。

起初,這一切都很好,但是通常在房間和場景中瀏覽然后嘗試刪除場景后,它將崩潰。 如果玩了足夠長的時間,它將不可避免地崩潰。 它僅在刪除場景時發生。 如果按下編輯按鈕並刪除一個場景並且該場景有效,則該編輯會話中的以下所有刪除將始終有效。 它只會在第一次刪除編輯會話時崩潰。

我得到的錯誤是一個奇怪的錯誤:

由於未捕獲的異常“ NSInvalidArgumentException”而終止應用程序,原因:“-[__ NSCFType controllerWillChangeContent:]:無法識別的選擇器已發送到實例0x5e02d70”

該錯誤的第一部分有時會更改。 有時是__NSCFType ,有時是CALayer 僅在刪除場景時才會發生此錯誤。 添加場景可以100%完成。

我已經閱讀了另一篇有關stackoverflow的文章,該文章表明這​​類錯誤可能來自內存管理問題。 我已經仔細檢查了代碼,並使用檢漏儀在Instruments上運行了該代碼。 沒有泄漏。

還有什么我可以檢查的嗎? 有任何想法嗎?

這是相關的代碼。

從ScenesTableViewController.m:

// used to show/hide the add button

- (void)setEditing:(BOOL)editing animated:(BOOL)animate
{
    [super setEditing:editing animated:animate];
    if(editing)
    {
        self.navigationItem.leftBarButtonItem = addButton;
    }
    else
    {
        self.navigationItem.leftBarButtonItem = nil;
    }
}

// called when the add button is pressed

- (void)addAction {
    NSEntityDescription *myContentEntity = [NSEntityDescription entityForName:@"Scene" inManagedObjectContext:managedObjectContext];
    Scene *contentToSave = [[Scene alloc] initWithEntity:myContentEntity insertIntoManagedObjectContext:managedObjectContext];
    [contentToSave setValue:@"New Scene" forKey:@"Name"];
    [parentRoom addRoomToScenesObject:contentToSave];

    NSError *error;
    if (![managedObjectContext save:&error]) {
        NSLog(@"Unresolved error %@, %@", error, [error userInfo]);
        exit(-1);
    }
    [contentToSave release];
}

// delegate method that's being sent unrecognised selectors

- (void)controllerWillChangeContent:(NSFetchedResultsController *)controller {
    // The fetch controller is about to start sending change notifications, so prepare the table view for updates.
    [self.tableView beginUpdates];
}

// cell display code

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
    static NSString *CellIdentifier = @"Cell";
    UITableViewCell *cell = nil; 
    cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier]; 
    if (!cell) {
        cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle
                                       reuseIdentifier:CellIdentifier] autorelease]; 
        [cell setAccessoryType:UITableViewCellAccessoryDisclosureIndicator];
    }
    [self configureCell:cell atIndexPath:indexPath]; 
    return cell;
}

- (void)configureCell:(UITableViewCell *)cell atIndexPath:(NSIndexPath *)indexPath {
    NSManagedObject *mo = nil;
    NSString *temp = nil;
    mo = [fetchedResultsController objectAtIndexPath:indexPath];
    temp = [mo valueForKey:@"Name"];
    [[cell textLabel] setText:temp];
}

// cell editing code

- (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath {

    if (editingStyle == UITableViewCellEditingStyleDelete) {
        // Delete the managed object at the given index path.
        [managedObjectContext deleteObject:[fetchedResultsController objectAtIndexPath:indexPath]];

        NSError *error;
        if (![managedObjectContext save:&error]) {
            // Update to handle the error appropriately.
            NSLog(@"Unresolved error %@, %@", error, [error userInfo]);
            exit(-1);  // Fail
        }
    }   
    else if (editingStyle == UITableViewCellEditingStyleInsert) {
        // Create a new instance of the appropriate class, insert it into the array, and add a new row to the table view
    }    
}

// NSFetchedResultsController code

- (NSFetchedResultsController *)fetchedResultsController {

    if (fetchedResultsController != nil) {
        return fetchedResultsController;
    }

    /*
     Set up the fetched results controller.
     */
    // Create the fetch request for the entity.
    NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
    // Edit the entity name as appropriate.
    NSEntityDescription *entity = [NSEntityDescription entityForName:@"Scene" inManagedObjectContext:managedObjectContext];
    NSSortDescriptor *nameDescriptor = [[NSSortDescriptor alloc] initWithKey:@"Name" ascending:YES];
    NSArray *sortDescriptors = [[NSArray alloc] initWithObjects:nameDescriptor, nil];
    NSPredicate *predicate = [NSPredicate predicateWithFormat:@"(SceneToRoom == %@)", parentRoom];

    [fetchRequest setSortDescriptors:sortDescriptors];   
    [fetchRequest setPredicate:predicate];
    [fetchRequest setEntity:entity];

    // Edit the section name key path and cache name if appropriate.
    // nil for section name key path means "no sections".
    NSFetchedResultsController *aFetchedResultsController = [[NSFetchedResultsController alloc] initWithFetchRequest:fetchRequest managedObjectContext:managedObjectContext sectionNameKeyPath:nil cacheName:nil];
    aFetchedResultsController.delegate = self;
    self.fetchedResultsController = aFetchedResultsController;

    [aFetchedResultsController release];
    [fetchRequest release];    
    [nameDescriptor release];
    [sortDescriptors release];

    return fetchedResultsController;
} 

該錯誤很可能來自具有已釋放委托的NSFetchedResultsController 您是否有一個UIViewController已發布但未發布關聯的NSFetchedResultsController

即使我也面臨同樣的問題。 但是對於iOS 4.2,問題在於NSError已初始化,因此將其視為垃圾,並且在更新/插入時,

if (![managedObjectContext save:&error]) {
        NSLog(@"Unresolved error %@, %@", error, [error userInfo]);
        exit(-1);
    }

因此,在保存時,iOS將錯誤視為垃圾,因此將其視為異常。 嘗試將其初始化為nil。 它解決了我的問題。 該問題僅在4.2iOS上可見。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM