Core Data Tutorial抛出错误,插入nil

时间:2014-05-27 00:16:47

标签: ios objective-c core-data

我在youtube上关注Dennis Roberson的教程“CoreData Part 1 and 2”。 伟大的教程顺便说一句! Thanx @ Dennis。

无论如何,我一定是搞砸到了某个地方而且我找不到它的位置。

在我的“PatientView”屏幕中,当我点击+时,它会转到addPatient-Screen, 如果我没有输入任何数据并点击取消,它会尝试在我的内部执行“回滚”操作 “cancelAndDismiss”方法(在CoreViewController.m中找到) 我在那一行设置了断点,当我执行该行时,它崩溃了。 当然,我可以单步执行其他一些命令,因为它会收集该步骤的数据,但它永远不会到达下一行。 这是完全

的方法
-(void)cancelAndDismiss
{

    [self.managedObjectContext rollback];
    [self dismissViewControllerAnimated:YES completion:nil];
}

这是我的错误日志的输出:

2014-05-26 18:58:01.118 CoreData[2287:60b] Objects returned: 0
2014-05-26 18:58:02.851 CoreData[2287:60b] _managedObjectContext: <NSManagedObjectContext: 0x8f786e0>
2014-05-26 18:58:02.868 CoreData[2287:60b] Objects returned: 1
2014-05-26 18:58:02.869 CoreData[2287:60b] In here NOW
2014-05-26 18:58:02.871 CoreData[2287:60b] tableView Cell - Lastname: (null)
2014-05-26 18:58:02.871 CoreData[2287:60b] tableView Cell - Firstname: (null)
2014-05-26 18:58:14.840 CoreData[2287:60b] _managedObjectContext: <NSManagedObjectContext: 0x8f786e0>
2014-05-26 19:01:05.959 CoreData[2287:60b] *** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '*** -[__NSPlaceholderArray initWithObjects:count:]: attempt to insert nil object from objects[0]'
*** First throw call stack:
(
    0   CoreFoundation                      0x01b5b1e4 __exceptionPreprocess + 180
    1   libobjc.A.dylib                     0x018da8e5 objc_exception_throw + 44
    2   CoreFoundation                      0x01b0f206 -[__NSPlaceholderArray initWithObjects:count:] + 390
    3   CoreFoundation                      0x01b32b89 +[NSArray arrayWithObject:] + 73
    4   CoreData                            0x000035ca -[PatientsTableViewController controller:didChangeObject:atIndexPath:forChangeType:newIndexPath:] + 394
    5   CoreData                            0x0036790b -[NSFetchedResultsController(PrivateMethods) _managedObjectContextDidChange:] + 2795
    6   Foundation                          0x015ad049 __57-[NSNotificationCenter addObserver:selector:name:object:]_block_invoke + 40
    7   CoreFoundation                      0x01bb6f04 __CFNOTIFICATIONCENTER_IS_CALLING_OUT_TO_AN_OBSERVER__ + 20
    8   CoreFoundation                      0x01b0eefb _CFXNotificationPost + 2859
    9   Foundation                          0x014e6e41 -[NSNotificationCenter postNotificationName:object:userInfo:] + 98
    10  CoreData                            0x0026aa13 -[NSManagedObjectContext(_NSInternalNotificationHandling) _postObjectsDidChangeNotificationWithUserInfo:] + 83
    11  CoreData                            0x00306173 -[NSManagedObjectContext rollback] + 1939
    12  CoreData                            0x00005804 -[CoreViewController cancelAndDismiss] + 84
    13  CoreData                            0x0000512b -[AddPatientViewController cancel:] + 107
    14  libobjc.A.dylib                     0x018ec880 -[NSObject performSelector:withObject:withObject:] + 77
    15  UIKit                               0x0059c3b9 -[UIApplication sendAction:to:from:forEvent:] + 108
    16  UIKit                               0x008898df -[UIBarButtonItem(UIInternal) _sendAction:withEvent:] + 139
    17  libobjc.A.dylib                     0x018ec880 -[NSObject performSelector:withObject:withObject:] + 77
    18  UIKit                               0x0059c3b9 -[UIApplication sendAction:to:from:forEvent:] + 108
    19  UIKit                               0x0059c345 -[UIApplication sendAction:toTarget:fromSender:forEvent:] + 61
    20  UIKit                               0x0069dbd1 -[UIControl sendAction:to:forEvent:] + 66
    21  UIKit                               0x0069dfc6 -[UIControl _sendActionsForEvents:withEvent:] + 577
    22  UIKit                               0x0069d243 -[UIControl touchesEnded:withEvent:] + 641
    23  UIKit                               0x005dbddd -[UIWindow _sendTouchesForEvent:] + 852
    24  UIKit                               0x005dc9d1 -[UIWindow sendEvent:] + 1117
    25  UIKit                               0x005ae5f2 -[UIApplication sendEvent:] + 242
    26  UIKit                               0x00598353 _UIApplicationHandleEventQueue + 11455
    27  CoreFoundation                      0x01ae477f __CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE0_PERFORM_FUNCTION__ + 15
    28  CoreFoundation                      0x01ae410b __CFRunLoopDoSources0 + 235
    29  CoreFoundation                      0x01b011ae __CFRunLoopRun + 910
    30  CoreFoundation                      0x01b009d3 CFRunLoopRunSpecific + 467
    31  CoreFoundation                      0x01b007eb CFRunLoopRunInMode + 123
    32  GraphicsServices                    0x03a0d5ee GSEventRunModal + 192
    33  GraphicsServices                    0x03a0d42b GSEventRun + 104
    34  UIKit                               0x0059af9b UIApplicationMain + 1225
    35  CoreData                            0x00004ebd main + 141
    36  libdyld.dylib                       0x021a2701 start + 1
)
libc++abi.dylib: terminating with uncaught exception of type NSException
(lldb)

要完成列表,请参阅以下文件:

CoreViewController.m

#import "CoreViewController.h"
#import "AppDelegate.h"



@interface CoreViewController ()

@property (nonatomic, strong)NSManagedObjectContext *managedObjectContext;

@end

@implementation CoreViewController

- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
    self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
    if (self) {
        // Custom initialization
    }
    return self;
}


- (NSManagedObjectContext*)managedObjectContext {

    return [(AppDelegate*) [[UIApplication sharedApplication]delegate]managedObjectContext];
}


- (void)viewDidLoad
{
    [super viewDidLoad];
    // Do any additional setup after loading the view.
}

- (void)didReceiveMemoryWarning
{
    [super didReceiveMemoryWarning];
    // Dispose of any resources that can be recreated.
}

/*
#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.
}
*/


-(void)cancelAndDismiss
{

    [self.managedObjectContext rollback];
    [self dismissViewControllerAnimated:YES completion:nil];
}


-(void)saveAndDismiss {

    NSError *error = nil;
    if ([self.managedObjectContext hasChanges]) {
        if (![self.managedObjectContext save:&error]) {                 // save failed
            NSLog(@"Save failed: %@", [error localizedDescription]);
        } else {                                                        // save succeeded
            NSLog(@"Save Succeeded");
        }
    }
    [self dismissViewControllerAnimated:YES completion:nil];

}

@end

PatientsTableViewController.m

#import "PatientsTableViewController.h"
#import "AppDelegate.h"
#import "AddPatientViewController.h"

@interface PatientsTableViewController ()

@property (nonatomic, strong) NSManagedObjectContext *managedObjectContext;
@property (nonatomic, strong) NSFetchedResultsController *fetchedResultsController;


@end

@implementation PatientsTableViewController

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

- (NSManagedObjectContext*)managedObjectContext
{

    return [(AppDelegate*)[[UIApplication sharedApplication]delegate]managedObjectContext];
}

- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
    if ([[segue identifier]isEqualToString:@"addPatient"]) {

        UINavigationController *navigationController = segue.destinationViewController;
        AddPatientViewController *addPatientViewController = (AddPatientViewController*) navigationController.topViewController;

        Patient *addPatient = [NSEntityDescription insertNewObjectForEntityForName:@"Patient" inManagedObjectContext:[self managedObjectContext]];

        addPatientViewController.addPatient = addPatient;
    }
}

- (void)viewDidLoad
{
    [super viewDidLoad];

    NSError *error = nil;
    if (![[self fetchedResultsController]performFetch:&error]) {
        NSLog(@"Error! %@", error);
        abort();
    }

}

- (void)didReceiveMemoryWarning
{
    [super didReceiveMemoryWarning];
    // Dispose of any resources that can be recreated.
}

#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];
    NSLog(@"Objects returned: %d", [sectionInfo numberOfObjects]);
    return [sectionInfo numberOfObjects];
}


- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
    NSLog(@"In here NOW");
    static NSString *CellIdentifier = @"Cell";
    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier forIndexPath:indexPath];

    // Configure the cell...
    Patient *patient = [self.fetchedResultsController objectAtIndexPath:indexPath];

    cell.textLabel.text = patient.patientLastName;
    cell.detailTextLabel.text = patient.patientFirstName;

    NSLog(@"tableView Cell - Lastname: %@", patient.patientLastName);
    NSLog(@"tableView Cell - Firstname: %@", patient.patientFirstName);

    return cell;
}


/*
// 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
{
    if (editingStyle == UITableViewCellEditingStyleDelete) {
        // Delete the row from the data source

        NSManagedObjectContext *context = [self managedObjectContext];

        Patient *patientToDelete = [self.fetchedResultsController objectAtIndexPath:indexPath];

        [context deleteObject:patientToDelete];

        NSError *error = nil;
        if (![context save:&error]) {
            NSLog(@"Error! %@", error);
        }
    }

}


/*
// 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.
}
*/

#pragma mark - Fetched Results Controller Section

- (NSFetchedResultsController*)fetchedResultsController {

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

    NSFetchRequest *fetchRequest = [[NSFetchRequest alloc]init];
    NSManagedObjectContext *context = [self managedObjectContext];
    NSEntityDescription *entity = [NSEntityDescription entityForName:@"Patient" inManagedObjectContext:context];

    [fetchRequest setEntity:entity];

    NSSortDescriptor *sortDescriptor = [[NSSortDescriptor alloc]initWithKey:@"patientLastName" ascending:YES];
    NSArray *sortDescriptors = [[NSArray alloc]initWithObjects:sortDescriptor, nil];

    fetchRequest.sortDescriptors = sortDescriptors;

    _fetchedResultsController = [[NSFetchedResultsController alloc]initWithFetchRequest:fetchRequest managedObjectContext:context sectionNameKeyPath:nil cacheName:nil];
    _fetchedResultsController.delegate = self;

    return _fetchedResultsController;
}

#pragma mark - Fetched Results Controller Delegates

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

    [self.tableView beginUpdates];
}

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

    [self.tableView endUpdates];
}

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

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

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

        case NSFetchedResultsChangeUpdate: {
            Patient *changePatient = [self.fetchedResultsController objectAtIndexPath:indexPath];
            UITableViewCell *cell = [tableView cellForRowAtIndexPath:indexPath];
            cell.textLabel.text = changePatient.patientLastName;
        }
            break;

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

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

    switch (type) {
        case NSFetchedResultsChangeInsert:
            [self.tableView deleteSections:[NSIndexSet indexSetWithIndex:sectionIndex] withRowAnimation:UITableViewRowAnimationFade];
            break;

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

@end

@EDIT: 我把它缩小了。它来自这段代码:

- (NSManagedObjectContext *)managedObjectContext
{
/*    if (_managedObjectContext != nil) {
        NSLog(@"_managedObjectContext: %@", _managedObjectContext);
        return _managedObjectContext;
    }
*/
    NSPersistentStoreCoordinator *coordinator = [self persistentStoreCoordinator];
    if (coordinator != nil) {
        _managedObjectContext = [[NSManagedObjectContext alloc] init];
        [_managedObjectContext setPersistentStoreCoordinator:coordinator];
    }
    return _managedObjectContext;
}

在我的AppDelegate.m文件中。正如你所看到的,我评论了它的顶部部分,如果没有那段代码片段就会很棒,有了它,就会崩溃。

这是AppDelegate.m文件的顶部,这次不是整个代码; - )

#import "AppDelegate.h"

@implementation AppDelegate

@synthesize managedObjectContext = _managedObjectContext;
@synthesize managedObjectModel = _managedObjectModel;
@synthesize persistentStoreCoordinator = _persistentStoreCoordinator;

我希望有人可以帮助我并指出正确的方向,因为我正在黑暗中攻击: - /

谢谢大家,对不起代码太多了

1 个答案:

答案 0 :(得分:4)

查看异常附带的消息:

  

-[__NSPlaceholderArray initWithObjects:count:]: attempt to insert nil object from objects[0]'

__NSPlaceholderArray不是你的类,所以让我们看一下堆栈跟踪......

2   CoreFoundation                      0x01b0f206 -[__NSPlaceholderArray initWithObjects:count:] + 390
3   CoreFoundation                      0x01b32b89 +[NSArray arrayWithObject:] + 73
4   CoreData                            0x000035ca -[PatientsTableViewController controller:didChangeObject:atIndexPath:forChangeType:newIndexPath:] + 394

现在我们到了某个地方......你拥有-[PatientsTableViewController controller:didchangeObject:...]的代码,该方法在四个不同的地方调用+[NSArray arrayWithObject:]。这些行中至少有一行是异常的直接原因。查看the documentation for that method,您会发现在某些情况下,indexPathnewIndexPath都可以nil。具体来说,描述newIndexPath的行说:

  

插入或移动对象的目标路径(删除时此值为nil)。

再看一下代码,你得到了:

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

因此,问题在于您将newIndexPath(已记录为nil要删除)传递给+[NSArray arrayWithObject:]。您可能打算通过indexPath

同样,您可能并不是要在indexPath案例中使用NSFetchedResultsChangeMove来删除和插入。删除可能indexPath,插入newIndexPath。您的代码(减去错误)几乎与NSFetchedResultsControllerDelegate {{1}}中的示例完全相同,因此请查看该代码以获取更多帮助。