我在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;
我希望有人可以帮助我并指出正确的方向,因为我正在黑暗中攻击: - /
谢谢大家,对不起代码太多了
答案 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,您会发现在某些情况下,indexPath
和newIndexPath
都可以nil
。具体来说,描述newIndexPath
的行说:
插入或移动对象的目标路径(删除时此值为
nil
)。
再看一下代码,你得到了:
case NSFetchedResultsChangeDelete:
[tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:newIndexPath] withRowAnimation:UITableViewRowAnimationFade];
break;
因此,问题在于您将newIndexPath
(已记录为nil
要删除)传递给+[NSArray arrayWithObject:]
。您可能打算通过indexPath
。
同样,您可能并不是要在indexPath
案例中使用NSFetchedResultsChangeMove
来删除和插入。删除可能indexPath
,插入newIndexPath
。您的代码(减去错误)几乎与NSFetchedResultsControllerDelegate
{{1}}中的示例完全相同,因此请查看该代码以获取更多帮助。