4

當用戶按下Edit時,我的UITableView在頂部添加一個插入行(帶有綠色加號),並將所有其他行放入刪除模式(紅色減號)。或者,用戶可以輕掃即可刪除而無需按下編輯按鈕。我使用幾個Ivars來跟蹤表格是否處於編輯模式,或者按下編輯按鈕,並相應地執行操作(例如,更新numberOfRowsInTableView:當按下Edit時更多插入行)。爲什麼我不能刪除我的UITableView的底部行?

除了事物之外,一切都很完美:在編輯模式下(即用戶明確地點擊編輯按鈕,插入行出現在頂部),如果用戶試圖刪除底行,則下一行取而代之的是刪除。刪除任何其他行很好。

編輯 - 它似乎刪除上面的行,但如果我立即退出,並重新加載應用程序,它原來的底行已經畢竟。所以我猜我的UITableView與我的NSFetchedResultsController不同步。

下面是我使用的代碼:

#import "ChecklistsViewController.h" 
#import "Checklist.h" 

@interface ChecklistsViewController (private) 
- (void)configureCell:(UITableViewCell *)cell atIndexPath:(NSIndexPath *)indexPath; 
- (void)addingView; 
@end 


@implementation ChecklistsViewController 

@synthesize category, managedObjectContext, fetchedResultsController; 


- (id)initWithStyle:(UITableViewStyle)style 
{ 
    self = [super initWithStyle:style]; 
    if (self) { 
     editingFromSwipe = NO; 
     tableIsEditing = NO; 
    } 
    return self; 
} 

- (void)dealloc 
{ 
    [category release]; 
    [managedObjectContext release]; 
    [fetchedResultsController release]; 
    [super dealloc]; 
} 

#pragma mark - View lifecycle 

- (void)viewDidLoad 
{ 
    [super viewDidLoad]; 
    editingFromSwipe = NO; 
    tableIsEditing = NO; 
    self.navigationItem.rightBarButtonItem = self.editButtonItem;  
    self.tableView.allowsSelectionDuringEditing = YES; 
} 


- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation 
{ 
    // Return YES for supported orientations 
    return (interfaceOrientation == UIInterfaceOrientationPortrait); 
} 


#pragma mark - Table view data source 

- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView 
{ 
    return [[self.fetchedResultsController sections] count]; 
} 

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section 
{ 
    id <NSFetchedResultsSectionInfo> sectionInfo = [[self.fetchedResultsController sections] objectAtIndex:section]; 
    int rows = [sectionInfo numberOfObjects]; 

    if (self.editing) { 
     if (!editingFromSwipe && tableIsEditing) { 
      return rows +1; 
     } 
     return rows; 
    } 
    tableIsEditing = NO; 
    return rows; 
} 

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath 
{ 
    static NSString *CellIdentifier = @"Cell"; 

    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier]; 
    if (cell == nil) { 
     cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:CellIdentifier] autorelease]; 
    } 

    // Configure the cell... 
    cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator; 


    NSLog(@"Should go into if statement here! \n"); 

    if (tableView.editing) { // 
     if ((indexPath.row == 0) && (!editingFromSwipe)) { 
      NSLog(@"Configuring Add Button Cell while editing \n"); 
      cell.textLabel.text = @"Add New Checklist"; 
      cell.detailTextLabel.text = nil; 
     } 
     else { 
      NSLog(@"Configuring other cells while editing \n"); 
      [self configureCell:cell atIndexPath:indexPath]; 
     } 

    } 
    else { 
     NSLog(@"Configuring Cell Normally While Not Editing \n"); 
     [self configureCell:cell atIndexPath:indexPath]; 
    } 


    return cell; 
} 

- (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath 
{ 
    if (editingStyle == UITableViewCellEditingStyleDelete) 
    { 
     // Delete the managed object for the given index path 
     NSManagedObjectContext *context = [self.fetchedResultsController managedObjectContext]; 

     int numberOfRows = [self tableView:tableView numberOfRowsInSection:indexPath.section]; 
     int rowBeingDeleted = indexPath.row +1; 

     if (tableIsEditing && !editingFromSwipe && numberOfRows == rowBeingDeleted) { 
      [context deleteObject:[self.fetchedResultsController objectAtIndexPath:[NSIndexPath indexPathForRow:indexPath.row-1 inSection:indexPath.section]]]; 
     } 
     else { 
      [context deleteObject:[self.fetchedResultsController objectAtIndexPath:indexPath]]; 
     } 

     // Save the context. 
     NSError *error = nil; 
     if (![context save:&error]) 
     { 
      // TO DO: Fix error code. 
      NSLog(@"Unresolved error %@, %@", error, [error userInfo]); 
      abort(); 
     } 
    }  
    else if (editingStyle == UITableViewCellEditingStyleInsert) { 
     [self addingView];   
    } 
} 

- (UITableViewCellEditingStyle)tableView:(UITableView *)tableView editingStyleForRowAtIndexPath:(NSIndexPath *)indexPath { 
    int row = indexPath.row; 

    if (self.editing && row == 0) { 
     if (!editingFromSwipe && tableIsEditing) { 
      return UITableViewCellEditingStyleInsert; 
     } 
     else if (editingFromSwipe) { 
      return UITableViewCellEditingStyleDelete; 
     } 

    } 
    return UITableViewCellEditingStyleDelete; 
} 


- (void)tableView:(UITableView *)tableView willBeginEditingRowAtIndexPath:(NSIndexPath *)indexPath 
{ 
    editingFromSwipe = YES; 
    [super tableView:tableView willBeginEditingRowAtIndexPath:indexPath]; 
} 

- (void)tableView:(UITableView *)tableView didEndEditingRowAtIndexPath:(NSIndexPath *)indexPath 
{ 
    [super tableView:tableView didEndEditingRowAtIndexPath:indexPath]; 
    editingFromSwipe = NO; 
} 


- (void)setEditing:(BOOL)editing animated:(BOOL)animated 
{ 
    [super setEditing:editing animated:animated]; 

    NSArray *addRow = [NSArray arrayWithObjects:[NSIndexPath indexPathForRow:0 inSection:0], nil]; 
    [self.tableView beginUpdates]; 

    if (!editingFromSwipe) { 
     if (editing) { 
      tableIsEditing = YES; 
      [self.tableView insertRowsAtIndexPaths:addRow withRowAnimation:UITableViewRowAnimationLeft]; 
     } 
     else { 
      [self.tableView deleteRowsAtIndexPaths:addRow withRowAnimation:UITableViewRowAnimationLeft]; 
     } 
    } 
    [self.tableView endUpdates]; 
} 


#pragma mark - Table view delegate 

- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath 
{ 
    if (indexPath.row != 0) { 
     TO DO: Code for when row is selected 
    } 
} 


#pragma mark - Data 


- (void)configureCell:(UITableViewCell *)cell atIndexPath:(NSIndexPath *)indexPath 
{ 
    Checklist *aChecklist = [self.fetchedResultsController objectAtIndexPath:indexPath]; 
    cell.textLabel.text = aChecklist.name; 
    cell.detailTextLabel.text = aChecklist.category.name; 
} 


- (void) addingView// :(id)sender 
{ 
    AddingViewController *viewController = [[AddingViewController alloc] initWithNibName:@"AddingViewController" bundle:nil]; 

    viewController.delegate = self; 
    viewController.title = @"Add Checklist"; 

    // Create the navigation controller and present it modally 
    UINavigationController *navigationController = [[UINavigationController alloc] initWithRootViewController:viewController]; 
    [self presentModalViewController:navigationController animated:YES]; 

    viewController.textLabel.text = @"Enter new checklist name"; 

    [navigationController release]; 
    [viewController release]; 
} 


#pragma mark - AddingViewDelegate 


- (void)addingViewController:(AddingViewController *)addingViewController didAdd:(NSString *)itemAdded 
{ 
    if (itemAdded != nil) { 

     // Turn off editing mode. 
     if (self.editing) [self.navigationController setEditing:NO animated:NO]; 

     // Add the category name to our model and table view. 

     // Create a new instance of the entity managed by the fetched results controller. 
     NSManagedObjectContext *context = [self.fetchedResultsController managedObjectContext]; 
     NSEntityDescription *entity = [[self.fetchedResultsController fetchRequest] entity]; 
     Checklist *newChecklist = [NSEntityDescription insertNewObjectForEntityForName:[entity name] inManagedObjectContext:context]; 

     [category addChecklistsObject:newChecklist]; 

     newChecklist.name = itemAdded;   
     // [newChecklist setDateStamp:[NSDate date]]; 

     // Save the context. 
     NSError *error = nil; 
     if (![context save:&error]) 
     { 
      TO DO: fix error code. 
      NSLog(@"Unresolved error %@, %@", error, [error userInfo]); 
      abort(); 
     } 


    } 

    [self dismissModalViewControllerAnimated:YES]; 
} 


#pragma mark - Fetched results controller 

- (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:@"Checklist" inManagedObjectContext:self.managedObjectContext]; 
    [fetchRequest setEntity:entity]; 
    // Set 4* the predicate so we only see checklists for this category. 
    NSPredicate *requestPredicate = [NSPredicate predicateWithFormat:@"category.name = %@", self.category.name]; 
    [fetchRequest setPredicate:requestPredicate];  
    // Set the batch size to a suitable number. 
    [fetchRequest setFetchBatchSize:20];  
    // Edit the sort key as appropriate. 
    NSSortDescriptor *sortDescriptor = [[NSSortDescriptor alloc] initWithKey:@"name" ascending:YES]; 
    NSArray *sortDescriptors = [[NSArray alloc] initWithObjects:sortDescriptor, nil]; 
    [fetchRequest setSortDescriptors:sortDescriptors];  
    // 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:self.managedObjectContext 
                            sectionNameKeyPath:nil 
                              cacheName:nil]; 
    aFetchedResultsController.delegate = self; 
    self.fetchedResultsController = aFetchedResultsController; 


    [aFetchedResultsController release]; 
    [fetchRequest release]; 
    [sortDescriptor release]; 
    [sortDescriptors release]; 

    NSError *error = nil; 
    if (![self.fetchedResultsController performFetch:&error]) 
    { 
     // TO DO: error stuff 
     NSLog(@"Unresolved error %@, %@", error, [error userInfo]); 
     abort(); 
    } 

    return fetchedResultsController; 
} 


#pragma mark - Fetched results controller delegate 


- (void)controllerWillChangeContent:(NSFetchedResultsController *)controller 
{ 
    [self.tableView beginUpdates]; 
} 


- (void)controller:(NSFetchedResultsController *)controller didChangeSection:(id <NSFetchedResultsSectionInfo>)sectionInfo 
      atIndex:(NSUInteger)sectionIndex forChangeType:(NSFetchedResultsChangeType)type 
{ 
    switch(type) 
    { 
     case NSFetchedResultsChangeInsert: 
      [self.tableView insertSections:[NSIndexSet indexSetWithIndex:sectionIndex] withRowAnimation:UITableViewRowAnimationFade]; 
      break; 

     case NSFetchedResultsChangeDelete: 
      [self.tableView deleteSections:[NSIndexSet indexSetWithIndex:sectionIndex] withRowAnimation:UITableViewRowAnimationFade]; 
      break; 
    } 
} 


- (void)controller:(NSFetchedResultsController *)controller didChangeObject:(id)anObject 
     atIndexPath:(NSIndexPath *)indexPath forChangeType:(NSFetchedResultsChangeType)type 
     newIndexPath:(NSIndexPath *)newIndexPath 
{ 
    UITableView *tableView = self.tableView; 

    switch(type) 
    {  
     case NSFetchedResultsChangeInsert: 
      [tableView insertRowsAtIndexPaths:[NSArray arrayWithObject:newIndexPath] withRowAnimation:UITableViewRowAnimationFade]; 
      break; 

     case NSFetchedResultsChangeDelete: 
      [tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationFade]; 
      break; 

     case NSFetchedResultsChangeUpdate: 
      [self configureCell:[tableView cellForRowAtIndexPath:indexPath] atIndexPath:indexPath]; 
      break; 

     case NSFetchedResultsChangeMove: 
      [tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationFade]; 
      [tableView insertRowsAtIndexPaths:[NSArray arrayWithObject:newIndexPath]withRowAnimation:UITableViewRowAnimationFade]; 
      break; 
    } 
} 


- (void)controllerDidChangeContent:(NSFetchedResultsController *)controller 
{ 
    [self.tableView endUpdates]; 
} 

@end 
+0

下一次您要發佈378行代碼時,只需提供指向文件的鏈接即可。 – TechZen 2011-03-25 21:00:19

+0

我會告誡你不要讓你的tableviews複雜。我認爲試圖編輯tableview單元格內的數據幾乎總是一個錯誤。在桌面視圖中還有很多事情要做,以便進行編輯。要創建一個新行,請使用詳細視圖。這就是界面語法教會用戶所期望的。 – TechZen 2011-03-26 15:37:14

+0

@TechZen請原諒我對術語的陌生感,但是通過使用細節視圖,你的意思是什麼?我將'detail view'與加載全新視圖(例如,當用戶選擇父項時加載子實體表)相關聯。我如何將一行添加到具有詳細視圖的表格中? – 2011-03-27 12:30:24

回答

1

你的過錯設計它。你不應該在任何地方添加行,而是在邏輯上將它們放在表中。

抓取結果控制器(FRC)的整個點是使表視圖與數據同步。表中的行順序應反映fetchedObjects數組中的管理對象的順序。通過在底部或頂部插入一行,並添加一個不一定在邏輯上屬於該表頂部或底部的對象,正在打破該同步。

當您在addingViewController:didAdd:中添加新的託管對象時,FRC會提示它嘗試重新繪製表格。你試圖彌補這一點,但你真的不能。你所有的索引都會出來。

而不是使用一行來輸入新行。使用tableview頁眉或頁腳視圖。這樣,您可以凍結tableview,創建新對象,然後更新表格,新對象將顯示錶格中邏輯所屬的位置。

+0

謝謝。作爲一個新手,我不知道可以用表頭做到這一點,但有一點谷歌搜索似乎證實我應該能夠在那裏貼一個按鈕,並以更優雅的方式處理這個按鈕。我懷疑我以前看過的使用插入行的例子一定沒有使用過NSFetchedResultsController,那可能是我陷入困境的地方。當我回到我的身邊時,我會試試這個,然後我會回到這裏,讓你知道我是怎麼做到的。 – 2011-03-25 22:06:28

+0

它工作完美!我發現[本指南](http://osmorphis.blogspot.com/2009/04/putting-button-in-table.html)向表格添加按鈕,並且大約需要5分鐘才能實現。我也可以按照這種方式自定義按鈕,如果我更換我的表格,它應該可以輕鬆地「縮放」。謝謝! – 2011-03-28 14:41:10

1

爲了不把行混在一起,我建議把插入行放在它自己的部分。既然你明明只是使用一個部分中,您知道您發送到FRC部分應始終爲0的代碼是一樣簡單:

[context deleteObject:[self.fetchedResultsController objectAtIndexPath:[NSIndexPath indexPathForRow:indexPath.row inSection:0]]]; 

TechZen的解決方案也將工作,所以你選擇哪種解決方案完全關於你喜歡什麼樣的設計。 TechZen的解決方案不會影響到多個部分,但是此解決方案也可以修改以支持多個部分。

+0

非常感謝你的幫助Erik。最後,我已經使用了TechZen的建議,但在過去的幾天裏我已經從您那裏學到了很多金額,而且我的一般編程知識對它來說更好! – 2011-03-28 14:39:31

2

您可以將靜態單元添加到從NSFetchedResultsController獲取其數據的UITableViews。但要做到這一點,您必須調整幾乎所有在UITableViewDelegateUITableViewDataSourceNSFetchedResultsControllerDelegate方法之一中使用的NSIndexPath。

我添加了一些幫助器方法,將tableview的indexpath轉換爲抓取的resultscontroller的indexpath,反之亦然。

- (NSIndexPath *)tableIndexPathFromNSFRCIndexPath:(NSIndexPath *)ip { 
    if (editingMode && ip.section == 0) { 
     NSIndexPath *newIP = [NSIndexPath indexPathForRow:ip.row+1 inSection:ip.section]; 
     return newIP; 
    } 
    return ip; 
} 

- (NSIndexPath *)nsfrcIndexPathFromTableIndexPath:(NSIndexPath *)ip { 
    if (editingMode && ip.section == 0) { 
     NSIndexPath *newIP = [NSIndexPath indexPathForRow:ip.row-1 inSection:ip.section]; 
     return newIP; 
    } 
    return ip; 
} 

,然後你不得不改變每一個通過從表中indexpath到fetchedresultscontroller或從FRC表方法:像這樣的東西可以,如果你想在上面添加行使用。我以兩個爲例。

- (void)controller:(NSFetchedResultsController *)controller didChangeObject:(id)anObject 
     atIndexPath:(NSIndexPath *)indexPath forChangeType:(NSFetchedResultsChangeType)type 
     newIndexPath:(NSIndexPath *)newIndexPath { 
    newIndexPath = [self tableIndexPathFromNSFRCIndexPath:newIndexPath]; 
    indexPath = [self tableIndexPathFromNSFRCIndexPath:indexPath]; 
    switch(type) { 
     case NSFetchedResultsChangeInsert: 
      [self.listTableView insertRowsAtIndexPaths:[NSArray arrayWithObject:newIndexPath] withRowAnimation:UITableViewRowAnimationFade]; 
      break; 
     case NSFetchedResultsChangeDelete: 
      [self.listTableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationFade]; 
      break; 
     case NSFetchedResultsChangeUpdate: 
      [self configureCell:[self.listTableView cellForRowAtIndexPath:indexPath] atIndexPath:indexPath]; 
      break; 
     case NSFetchedResultsChangeMove: 
      [self.listTableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationFade]; 
      [self.listTableView insertRowsAtIndexPaths:[NSArray arrayWithObject:newIndexPath]withRowAnimation:UITableViewRowAnimationFade]; 
      break; 
    } 
} 

- (void)tableView:(UITableView *)aTableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath{ 
    [aTableView deselectRowAtIndexPath:indexPath animated:YES]; 
    if (editingMode && indexPath.section == 0 && indexPath.row == 0) { 
     // Add New entry... 
    } 
    else { 
     indexPath = [self nsfrcIndexPathFromTableIndexPath:indexPath]; 
     NSManagedObject *selectedObject = [self.fetchedResultsController objectAtIndexPath:indexPath]); 
    } 
} 
+0

謝謝Fluchpunkt! – 2011-03-28 14:43:20

相關問題