更新Core Data Object无法正常工作

时间:2013-11-26 15:05:51

标签: ios iphone objective-c uitableview core-data

我是iOS开发/ CoreData的新手,并且已经搜索了我的具体问题的答案,但还没有找到答案。

我有一个TableView,包含我数据库中的一些对象。每个对象都有一个属性“name”。如果我打开其中一个对象的详细信息视图并使用“返回”按钮返回tableView,一切正常。如果我没有更改“名称”TextField并按“完成”按钮返回到我的tableView,它也可以工作。一旦我在“名称”TextField中做了一些更改,我就会收到此错误:

  

无效更新:第0节中的行数无效。更新后的现有部分中包含的行数(9)必须等于更新前该部分中包含的行数(9),或者减去从该部分插入或删除的行数(插入0,删除1),加上或减去移入或移出该部分的行数(0移入,0移出)。

为什么要删除某个对象?

这是我的DetailsS​​taticTableViewController.m的代码:

#import "WeinStaticTableViewController.h"
#import "Wein.h"
#import "JSMToolBox.h"

@interface WeinStaticTableViewController ()

@end

@implementation WeinStaticTableViewController
@synthesize nameTextView;
@synthesize landTextView;
@synthesize herstellerTextView;
@synthesize wein = _wein;

- (id)initWithStyle:(UITableViewStyle)style
{
   self = [super initWithStyle:style];
   if (self) {
     // Custom initialization
   }
   return self;
}

- (void)viewDidLoad
{
   [super viewDidLoad];

   if (self.wein != nil) {
      self.nameTextView.text = self.wein.name;
   }
}

- (void) viewDidDisappear:(BOOL)animated
{
   [[JSMCoreDataHelper managedObjectContext] rollback];
   [super viewDidDisappear:animated];
}

- (void)didReceiveMemoryWarning
{
   [super didReceiveMemoryWarning];
   // Dispose of any resources that can be recreated.
   [self setNameTextView:nil];
   [self setLandTextView:nil];
   [self setHerstellerTextView:nil];
   self.wein = nil;
}

- (IBAction)barButtonItemDonePressed:(id)sender
{
   NSLog(@"%s", __PRETTY_FUNCTION__);
   if (self.wein != nil) {
       self.wein.name = self.nameTextView.text;
       [JSMCoreDataHelper saveManagedObjectContext:[JSMCoreDataHelper managedObjectContext]];
   }
   [self.navigationController popViewControllerAnimated:YES];
}
@end

以下是我的JSMCoreDataHelper.m的代码:

#import "JSMCoreDataHelper.h"

@implementation JSMCoreDataHelper

+ (NSString*) directoryForDatabaseFilename
{
   return [NSHomeDirectory() stringByAppendingString:@"/Library/Private Documents"];
}

+ (NSString*) databaseFileName
{
   return @"database.sqlite";
}

+ (NSManagedObjectContext*) managedObjectContext
{
  static NSManagedObjectContext *managedObjectContext;
  if (managedObjectContext != nil) {
      return managedObjectContext;
  }

  NSError *error;
  // Verzeichnis unter dem das Datenbank-File abgespeichert werden soll, wird neu erzeugt, falls es noch nicht existiert.
  [[NSFileManager defaultManager] createDirectoryAtPath:[JSMCoreDataHelper directoryForDatabaseFilename] withIntermediateDirectories:YES attributes:nil error:&error];

  if (error) {
      NSLog(@"Fehler: %@", error.localizedDescription);
      return nil;
  }

  NSString *path = [NSString stringWithFormat:@"%@/%@", [JSMCoreDataHelper directoryForDatabaseFilename], [JSMCoreDataHelper databaseFileName]];
  NSURL *url = [NSURL fileURLWithPath:path];

  NSManagedObjectModel *managedModel = [NSManagedObjectModel mergedModelFromBundles:nil];

  NSPersistentStoreCoordinator *storeCoordinator = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel:managedModel];

  if (! [storeCoordinator addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:url options:nil error:&error]) {
      NSLog(@"Fehler: %@", error.localizedDescription);
      return nil;
  }

  managedObjectContext = [[NSManagedObjectContext alloc] init];
  managedObjectContext.persistentStoreCoordinator = storeCoordinator;

  return managedObjectContext;
}

+ (id) insertManagedObjectOfClass: (Class) aClass inManagedObjectContext: (NSManagedObjectContext*) managedObjectContext
{
   NSManagedObject *managedObject = [NSEntityDescription insertNewObjectForEntityForName:NSStringFromClass(aClass) inManagedObjectContext:managedObjectContext];
   return managedObject;
}

+ (BOOL) saveManagedObjectContext: (NSManagedObjectContext*) managedObjectContext
{
   NSError *error;
   if (! [managedObjectContext save:&error]) {
       NSLog(@"Fehler: %@", error.localizedDescription);
       return NO;
   }
   return YES;
}

+ (NSArray*) fetchEntitiesForClass: (Class) aClass withPredicate: (NSPredicate*) predicate inManagedObjectContext: (NSManagedObjectContext*) managedObjectContext
{
   NSError *error;
   NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
   NSEntityDescription *entityDescription = [NSEntityDescription entityForName:NSStringFromClass(aClass) inManagedObjectContext:managedObjectContext];
   fetchRequest.entity = entityDescription;
   fetchRequest.predicate = predicate;

   NSArray *items = [managedObjectContext executeFetchRequest:fetchRequest error:&error];
   if (error) {
       NSLog(@"Fehler: %@", error.localizedDescription);
       return nil;
   }
   return items;
}

+ (BOOL) performFetchOnFetchedResultsController: (NSFetchedResultsController*) fetchedResultsController
{
   NSError *error;
   if (! [fetchedResultsController performFetch:&error]) {
       NSLog(@"Fehler: %@", error.localizedDescription);
       return NO;
   }
   return YES;
}

@end

最后是我的MainTableViewController的numberOfSections和numberOfRowsInSection:

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

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
   // Return the number of rows in the section.
   return [[[self.fetchedResultsController sections] objectAtIndex:section] numberOfObjects];
}

任何线索都可以帮助......谢谢!

2 个答案:

答案 0 :(得分:1)

使用NSFetchedResultsController继承我的代码,这适用于管理CoreData的代码。

希望这有帮助。

#import "Person.h"
#import "mainViewController.h"
#import "JSMCoreDataHelper.h"
#import "staticInfoViewController.h"

@implementation mainViewController

- (void)viewDidLoad
{
    [super viewDidLoad];

    // Load From CoreData
    NSError *error;
    if (![[self fetchedResultsController] performFetch:&error]) {
        // Update to handle the error appropriately.
        NSLog(@"Unresolved error %@, %@", error, [error userInfo]);
        exit(-1);  // Fail
    }
}

#pragma mark - TableView DataSource

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

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
    // Return the number of rows in the section.
    return [[[self.fetchedResultsController sections] objectAtIndex:section] numberOfObjects];
}

- (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];
    }

    [self configureCell:cell atIndexPath:indexPath];

    return cell;
}

- (void)configureCell:(UITableViewCell *)cell atIndexPath:(NSIndexPath *)indexPath
{
    Person *p = [_fetchedResultsController objectAtIndexPath:indexPath];
    cell.textLabel.text = [NSString stringWithFormat:@"Name: %@", p.name];
}

#pragma mark - TableView Delegate

- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
    staticInfoViewController *info = [[staticInfoViewController alloc] initWithNibName:@"staticInfoViewController" bundle:[NSBundle mainBundle]];
    info.currentPerson = [_fetchedResultsController objectAtIndexPath:indexPath];
    [self.navigationController pushViewController:info animated:YES];
}

#pragma mark - Set NSFetchedResultsController

- (NSFetchedResultsController *)fetchedResultsController {

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

    NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
    NSEntityDescription *entity = [NSEntityDescription
                                   entityForName:@"Person" inManagedObjectContext:[JSMCoreDataHelper managedObjectContext]];
    [fetchRequest setEntity:entity];

    NSSortDescriptor *sort = [[NSSortDescriptor alloc]
                              initWithKey:@"name" ascending:YES];
    [fetchRequest setSortDescriptors:[NSArray arrayWithObject:sort]];

    [fetchRequest setFetchBatchSize:20];

    NSFetchedResultsController *theFetchedResultsController =
    [[NSFetchedResultsController alloc] initWithFetchRequest:fetchRequest
                                        managedObjectContext:[JSMCoreDataHelper managedObjectContext] sectionNameKeyPath:nil
                                                   cacheName:@"cache"];
    self.fetchedResultsController = theFetchedResultsController;
    _fetchedResultsController.delegate = self;

    return _fetchedResultsController;
}

#pragma mark - NSFetchedResultsController Delegate

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

- (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)controller:(NSFetchedResultsController *)controller didChangeSection:(id )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)controllerDidChangeContent:(NSFetchedResultsController *)controller {
    // The fetch controller has sent all current change notifications, so tell the table view to process all updates.
    [self.tableView endUpdates];
}

@end

答案 1 :(得分:0)

您在UI和核心数据中的数据数量错误。行计数dosnt匹配UI和核心数据。你已经daleted一行但UI / fetchresultcontroller不知道并尝试从数据库中读取它。更改后重新获取或实现获取结果控制器委托:

- (void)controller:(NSFetchedResultsController *)controller didChangeObject:(id)anObject atIndexPath:(NSIndexPath *)indexPath forChangeType:(NSFetchedResultsChangeType)type newIndexPath:(NSIndexPath *)newIndexPath;

- (void)controller:(NSFetchedResultsController *)controller didChangeSection:(id <NSFetchedResultsSectionInfo>)sectionInfo atIndex:(NSUInteger)sectionIndex forChangeType:(NSFetchedResultsChangeType)type;

- (void)controllerWillChangeContent:(NSFetchedResultsController *)controller;

- (void)controllerDidChangeContent:(NSFetchedResultsController *)controller;

不要忘记将获取结果控制器设置为self。(viel spass)