添加新项目后 UITableView 未更新(使用核心数据)

Posted

技术标签:

【中文标题】添加新项目后 UITableView 未更新(使用核心数据)【英文标题】:UITableView not being updated after adding new items (using Core Data) 【发布时间】:2014-05-14 11:06:12 【问题描述】:

我使用 Core Data 来跟踪一个简单的待办事项列表中的条目。我使用带有 UITextField 的简单 UIAlertView 供用户添加新条目。条目是使用 NSManagedObject 保存的,但即使在我运行 [self.tableView reloadData]; 之后,最新条目也不会添加到 tableview 中

这个 GIF 展示了它现在的工作原理:

头文件:

#import <UIKit/UIKit.h>

@interface PakkelisteViewController : UITableViewController <UIAlertViewDelegate>

@end

实现文件:

#import "PakkelisteViewController.h"
#import "AUFToDoItem.h"

@interface PakkelisteViewController ()

@property NSMutableArray *toDoItems;
-(IBAction)addNewToDoItem;

@end

@implementation PakkelisteViewController

- (id)initWithStyle:(UITableViewStyle)style

    self = [super initWithStyle:style];
    if (self) 
        // Custom initialization
    
    return self;


- (void)viewDidLoad

    [super viewDidLoad];

    // defaultTodos = [[NSMutableArray alloc] initWithObjects:@"Badetøy", @"Skrivesaker", @"Lommepenger", @"Godt humør", nil];

    self.toDoItems = [[NSMutableArray alloc] init];
    [self loadInitialData];

    // Uncomment the following line to preserve selection between presentations.
    // self.clearsSelectionOnViewWillAppear = NO;

    // Uncomment the following line to display an Edit button in the navigation bar for this view controller.
    // self.navigationItem.rightBarButtonItem = self.editButtonItem;


-(void)viewWillAppear:(BOOL)animated

    // Fetch the devices from persistent data store
    NSManagedObjectContext *managedObjectContext = [self managedObjectContext];
    NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] initWithEntityName:@"AUFToDoItem"];
    self.toDoItems = [[managedObjectContext executeFetchRequest:fetchRequest error:nil] mutableCopy];

    [self.tableView reloadData];


-(void)loadInitialData



-(IBAction)addNewToDoItem

    UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:@"Legg til ny" message:nil delegate:self cancelButtonTitle:@"Avbryt" otherButtonTitles:@"Legg til", nil];
    [alertView setAlertViewStyle:UIAlertViewStylePlainTextInput];

    [[alertView textFieldAtIndex:0] setPlaceholder:@"Rent undertøy"];
    [[alertView textFieldAtIndex:0] setAutocapitalizationType:UITextAutocapitalizationTypeSentences];

    [alertView show];


-(BOOL)alertViewShouldEnableFirstOtherButton:(UIAlertView *)alertView

    NSString *inputText = [[alertView textFieldAtIndex:0] text];

    if ([inputText length] > 0)
    
        return YES;
    
    else
    
        return NO;
    


-(void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex

    if (buttonIndex == 1)
    
        NSManagedObjectContext *context = [self managedObjectContext];

        // Create a new managed object
        NSManagedObject *toDoItem = [NSEntityDescription insertNewObjectForEntityForName:@"AUFToDoItem" inManagedObjectContext:context];
        [toDoItem setValue:[alertView textFieldAtIndex:0].text forKey:@"itemName"];
        [toDoItem setValue:[NSDate date] forKey:@"creationDate"];
        [toDoItem setValue:NO forKey:@"completed"];

        NSError *error = nil;
        // Save the object to persistent store
        if (![context save:&error]) 
            NSLog(@"Can't Save! %@ %@", error, [error localizedDescription]);
        

        [self dismissViewControllerAnimated:YES completion:nil];

        [self.tableView reloadRowsAtIndexPaths:[self.tableView indexPathsForVisibleRows] withRowAnimation:UITableViewRowAnimationFade];

//      [self.tableView reloadData];
    


- (void)didReceiveMemoryWarning

    [super didReceiveMemoryWarning];
    // Dispose of any resources that can be recreated.


#pragma mark - Table view data source

- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView

    // Return the number of sections.
    return 1;


- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section

    // Return the number of rows in the section.
    return self.toDoItems.count;


- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath

    static NSString *cellIdentifier = @"Cell";

    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:cellIdentifier];

    if (cell == nil)
    
        cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:cellIdentifier];
    

    NSManagedObject *toDoItem = [self.toDoItems objectAtIndex:indexPath.row];

    cell.textLabel.text = [toDoItem valueForKey:@"itemName"];

    if ((BOOL)[toDoItem valueForKey:@"completed"] == YES)
    
        cell.accessoryType = UITableViewCellAccessoryCheckmark;
    
    else
    
        cell.accessoryType = UITableViewCellAccessoryNone;
    

    return cell;


-(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath

    /*
    [tableView deselectRowAtIndexPath:indexPath animated:NO];

    AUFToDoItem *tappedItem = [self.toDoItems objectAtIndex:indexPath.row];
    tappedItem.completed = !tappedItem.completed;

    [tableView reloadRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationNone];
     */


-(NSManagedObjectContext *)managedObjectContext 
    NSManagedObjectContext *context = nil;
    id delegate = [[UIApplication sharedApplication] delegate];
    if ([delegate performSelector:@selector(managedObjectContext)]) 
        context = [delegate managedObjectContext];
    
    return context;



// Override to support conditional editing of the table view.
- (BOOL)tableView:(UITableView *)tableView canEditRowAtIndexPath:(NSIndexPath *)indexPath

    // Return NO if you do not want the specified item to be editable.
    return YES;


// Override to support editing the table view.
- (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath

    NSManagedObjectContext *context = [self managedObjectContext];

    if (editingStyle == UITableViewCellEditingStyleDelete) 

        [context deleteObject:[self.toDoItems objectAtIndex:indexPath.row]];

        NSError *error = nil;
        if (![context save:&error])
        
            NSLog(@"Can't delete! %@ %@", error, [error localizedDescription]);
            return;
        

        [self.toDoItems removeObjectAtIndex:indexPath.row];
        [self.tableView deleteRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationFade];
    


/*
// Override to support rearranging the table view.
- (void)tableView:(UITableView *)tableView moveRowAtIndexPath:(NSIndexPath *)fromIndexPath toIndexPath:(NSIndexPath *)toIndexPath


*/

/*
// Override to support conditional rearranging of the table view.
- (BOOL)tableView:(UITableView *)tableView canMoveRowAtIndexPath:(NSIndexPath *)indexPath

    // Return NO if you do not want the item to be re-orderable.
    return YES;

*/

/*
#pragma mark - Navigation

// In a storyboard-based application, you will often want to do a little preparation before navigation
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender

    // Get the new view controller using [segue destinationViewController].
    // Pass the selected object to the new view controller.

*/

@end

【问题讨论】:

if (cell == nil) in before add cell=nil;这个想法在我的代码中完美运行。 取消注释 [self.tableView reloadData];它会正常工作的。 @DarshanKunjadiya:不确定你的意思? @PrabhuNatarajan:没用。这就是为什么它被注释掉了,而我正在尝试reloadRowsAtIndexPaths: 方法。 您只需将该行添加到您的列表数组 [self.toDoItems addObject:toDoItem]; 【参考方案1】:

您还需要将新的 toDoItem 添加到您的数组中。试试这个:

    // Create a new managed object
    NSManagedObject *toDoItem = [NSEntityDescription insertNewObjectForEntityForName:@"AUFToDoItem" inManagedObjectContext:context];
    [toDoItem setValue:[alertView textFieldAtIndex:0].text forKey:@"itemName"];
    [toDoItem setValue:[NSDate date] forKey:@"creationDate"];
    [toDoItem setValue:NO forKey:@"completed"];

    [self.toDoItems addObject:toDoItem];
    [self.tableView reloadData];

【讨论】:

谢谢,这解决了。我怎么会忘记将它添加到数组中.. facepalm【参考方案2】:

您应该更新您的数据源self.toDoItems,因为它仍然与viewDidLoad 方法中的关闭相同。您只是将其保存在 CoreData 中,而不是刷新您的 dataSourse 和 [tableView reloadData] 不会做任何事情

【讨论】:

以上是关于添加新项目后 UITableView 未更新(使用核心数据)的主要内容,如果未能解决你的问题,请参考以下文章

添加行后如何更新 UITableView?

MapItemView 在 dataChanged 信号后未更新

IOS 蓝牙 LE 扫描设备未添加到 uitableview

在 swift uiTableView 中调用 reloadData() 后,旧项目剩余,新项目未显示

较小的 JSON 响应后更新 UITableView 时出错?

更新数据异步后重绘 UITableView