更新CoreData对象无法正常工作 [英] update CoreData Object not working correct

查看:52
本文介绍了更新CoreData对象无法正常工作的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我是iOS开发/ CoreData的新手,已经在寻找我的特定问题的答案,但是还没有找到答案。



我有一个TableView与我数据库中的一些对象。每个对象都有一个属性名称。如果我打开一个对象的详细信息视图,然后使用后退按钮返回tableView,则一切正常。如果我不对名称 TextField进行任何更改,然后按完成按钮返回到我的tableView,它也将起作用。我在名称文本字段中进行了一些更改后,立即收到以下错误消息:


无效的更新:第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){
//自定义初始化
}
返回self;
}

-(void)viewDidLoad
{
[super viewDidLoad];

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

-(void)viewDidDisappear:(BOOL)动画
{
[[JSMCoreDataHelpermanagedObjectContext]回滚];
[super viewDidDisappear:animated];
}

-(void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
//处理所有可以重新创建的资源。
[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:[JSMCoreDataHelpermanagedObjectContext]];
}
[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
{
静态NSManagedObjectContext * managedObjectContext;
if(managedObjectContext!= nil){
returnmanagedObjectContext;
}

NSError *错误;
//日期和日期数据库中的文件,wird neu erzeugt的werden soll属于存在的问题。
[[NSFileManager defaultManager] createDirectoryAtPath:[JSMCoreDataHelper directoryForDatabaseFilename] withIntermediateDirectories:YES属性:nil错误:& error];

if(error){
NSLog(@ Fehler:%@,error.localizedDescription);
归零;
}

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配置:无URL:url选项:无错误:&错误]){
NSLog(@ Fehler:%@,error.localizedDescription );
归零;
}

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

返回managedObjectContext;
}

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

+(BOOL)saveManagedObjectContext:(NSManagedObjectContext *)managedObjectContext
{
NSError * error;
if(![managedObjectContext save:& error]){
NSLog(@ Fehler:%@,error.localizedDescription);
返回否;
}
返回是;
}

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

NSArray * items = [managedObjectContext executeFetchRequest:fetchRequest错误:&错误];
if(error){
NSLog(@ Fehler:%@,error.localizedDescription);
归零;
}
退货商品;
}

+(布尔)performFetchOnFetchedResultsController:(NSFetchedResultsController *)fetchedResultsController
{
NSError * error;
if(![fetchedResultsController performFetch:& error]){
NSLog(@ Fehler:%@,error.localizedDescription);
返回否;
}
返回是;
}

@end

最后是numberOfSections和numberOfRowsInSection我的MainTableViewController:

 -(NSInteger)numberOfSectionsInTableView:(UITableView *)tableView 
{
//返回节数。
返回[[[self.fetchedResultsController部分]计数];
}

-(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
//返回该部分的行数。
返回[[[[self.fetchedResultsController部分] objectAtIndex:section] numberOfObjects];
}

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

解决方案

使用NSFetchedResultsController在我的代码中,这与您用于管理CoreData的代码配合得很好。



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

@implementation mainViewController

-(void)viewDidLoad
{
[super viewDidLoad];

//从CoreData加载
NSError * error;
if(![[[self fetchedResultsController] performFetch:& error]){
//更新以适当地处理错误。
NSLog(@未解决的错误%@,%@,错误,[错误userInfo]);
出口(-1); //失败
}
}

#pragma标记-TableView数据源

-(NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
//返回段数。
返回[[[self.fetchedResultsController部分]计数];
}

-(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
//返回该部分的行数。
返回[[[[self.fetchedResultsController部分] objectAtIndex:section] numberOfObjects];
}

-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
静态NSString * CellIdentifier = @ Cell ;
UITableViewCell * cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if(cell == nil){
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefaultDefaultIdentifier:CellIdentifier];
}

[self configureCell:cell atIndexPath:indexPath];

返回单元格;
}

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

#pragma mark-TableView委托

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

#pragma标记-设置NSFetchedResultsController

-(NSFetchedResultsController *)fetchedResultsController {

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

NSFetchRequest * fetchRequest = [[NSFetchRequest alloc] init];
NSEntityDescription *实体= [NSEntityDescription
entityForName:@ Person inManagedObjectContext:[JSMCoreDataHelpermanagedObjectContext]];
[fetchRequest setEntity:entity];

NSSortDescriptor * sort = [[NSSortDescriptor alloc]
initWithKey:@ name升序:是];
[fetchRequest setSortDescriptors:[NSArray arrayWithObject:sort]];

[fetchRequest setFetchBatchSize:20];

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

return _fetchedResultsController;
}

#pragma标记-NSFetchedResultsController委托

-(void)controllerWillChangeContent:(NSFetchedResultsController *)controller {
//获取控制器大约要开始发送更改通知,因此请准备表视图以进行更新。
[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];
休息时间;

case NSFetchedResultsChangeDelete:
[tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationFade];
休息时间;

case NSFetchedResultsChangeUpdate:
[self configureCell:[tableView cellForRowAtIndexPath:indexPath] atIndexPath:indexPath];
休息时间;

case NSFetchedResultsChangeMove:
[tableView deleteRowsAtIndexPaths:[NSArray
arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationFade];
[tableView insertRowsAtIndexPaths:[NSArray
arrayWithObject:newIndexPath] withRowAnimation:UITableViewRowAnimationFade];
休息时间;
}
}

-(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];
休息时间;

case NSFetchedResultsChangeDelete:
[self.tableView deleteSections:[NSIndexSet indexSetWithIndex:sectionIndex] withRowAnimation:UITableViewRowAnimationFade];
休息时间;
}
}

-(void)controllerDidChangeContent:(NSFetchedResultsController *)controller {
//获取控制器已发送了所有当前更改通知,因此请告知表查看以处理所有更新。
[self.tableView endUpdates];
}

@end


I'm new to iOS development/CoreData and have searched for an answer to my specific problem, but haven't found one yet.

I have a TableView with some Objects from my database. Each of the objects has an attribute "name". If I open the details view of one of the objects and go back to the tableView with the "back" Button everything works fine. It also works if I do no changes to the "name" TextField and press the "done" Button to get back to my tableView. As soon as I do some changes in the "name" TextField I get this error:

Invalid update: invalid number of rows in section 0. The number of rows contained in an existing section after the update (9) must be equal to the number of rows contained in that section before the update (9), plus or minus the number of rows inserted or deleted from that section (0 inserted, 1 deleted) and plus or minus the number of rows moved into or out of that section (0 moved in, 0 moved out).

Why is there an object being deleted?

Here is the code of my DetailsStaticTableViewController.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

Here is the code of my 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

And finally the numberOfSections and numberOfRowsInSection of my MainTableViewController:

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

Any clue could help...thank you !

解决方案

Heres my code using a NSFetchedResultsController, this works fine with your code for managing CoreData.

Hope this helps.

#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

这篇关于更新CoreData对象无法正常工作的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆