我的应用程序设置如下,我有两个视图控制器来自我的RootViewController - 一个带有两个按钮的简单主选择页面。顶部按钮将我发送到ViewController 1,在那里我拍摄照片并在有关照片的6个文本字段中插入数据。然后我点击一个保存按钮,将这些实体保存到我的ManagedObjectContext中的ManagedObjectModel TargetData。主页上的第二个按钮指向TableVIewController,我在其中调用NSFetchedResults sorta来更新TableView。
它工作得很好......至少在我运行一次TableViewController之前。我可以添加尽可能多的带有文本数据的照片,直到我显示TableViewController,此时,在离开页面时,TableViewController将仅显示第一次打开页面时加载的对象,而不是之后添加的任何项目。我做了一些搜索,发现第一次加载TableVIew后,fetchResults只看到它第一次加载时看到的很多实体。例如,如果我启动了应用程序,添加了5张带有文本的照片,然后运行了TableViewController,我会看到正确显示的5个项目。我可以回到主页然后添加另一张带文字的照片,但如果我回到TableVIewController,我只会看到我在打开TableViewController之前添加的5张照片。
在TableViewController的类中,我已经设置了我在TableViewController.m文件中使用它的所有普通方法。
完全无能为力。救命啊!
编辑:以下是我的一些代码
来自:将保存数据的ViewController.m
- (IBAction)saveTarget:(id)sender {
//Only save if there is an image other than the stock photo
if (self.image != [UIImage imageNamed:@"Photo-Video-Slr-camera-icon"]) {
//Grab the main ManagedObjectContext from the AppDelegate
sTCAppDelegate *appDelegate =[[UIApplication sharedApplication] delegate];
NSManagedObjectContext *context =[appDelegate managedObjectContext];
//Get the Target model from CoreData
[self setTarget:[NSEntityDescription insertNewObjectForEntityForName:@"TargetData" inManagedObjectContext:context]];
//Set the properties of the TargetData model
self.target.weaponData = self.weaponData.text;
self.target.bulletType = self.bulletType.text;
self.target.stanceType = self.stanceType.text;
self.target.distanceData = self.distanceData.text;
self.target.targetNotes = self.targetNotes.text;
self.target.sightType = self.sightType.text;
self.target.scoreData = [NSNumber numberWithInt:[self.scoreData.text intValue]];
//Set image to smaller size for storage
UIImage *image = [self resizeImage:self.image toWidth:50 andHeight:50];
//Save as PNG NSData for compression
self.target.targetImage = UIImagePNGRepresentation(image);
//Set a date property to use for organizing by most recently saved
self.target.timeStamp = [NSDate date];
//Save to context
NSError *error = nil;
if ( ![context save:&error] ){
NSLog(@"Unresolved error %@, %@", error, [error userInfo]);
abort();
}
//Jump back to main page
[self.navigationController popToRootViewControllerAnimated:YES];
//set images back to nil for next time AddTarget is opened
image = nil;
self.image = nil;
NSLog(@"Data Saved");
}
//Return alert if user has not entered a photo
else{
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"We're Sorry!" message:@"You must enter at least a photo to save target data." delegate:nil cancelButtonTitle:@"Okay" otherButtonTitles:nil];
[alert show];
}
}
来自:显示数据的TableViewController.m
#pragma mark - Table view data source
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
// Return the number of sections.
NSLog(@"number of sections:%lu",(unsigned long)[[self.fetchedResultsController sections] count]);
return [[self.fetchedResultsController sections] count];
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
id <NSFetchedResultsSectionInfo> sectionInfo = [[self.fetchedResultsController sections] objectAtIndex:section];
NSLog(@"%lu", [sectionInfo numberOfObjects]);
return [sectionInfo numberOfObjects];
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = @"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier forIndexPath:indexPath];
NSLog(@"Ran Cell Configure");
[self configureCell:cell atIndexPath:indexPath];
// Configure the cell...
return cell;
}
-(void)configureCell:(UITableViewCell *)cell atIndexPath:(NSIndexPath *)indexPath{
TargetData *target = [self.fetchedResultsController objectAtIndexPath:indexPath];
UIImage *image = [UIImage imageWithData:target.targetImage];
cell.imageView.image = image;
cell.textLabel.text = [NSString stringWithFormat:@"%@", target.scoreData];
cell.detailTextLabel.text = target.weaponData;
}
#pragma mark- FetchedResultsControllerDelegate Methods
- (NSFetchedResultsController *)fetchedResultsController {
if (_fetchedResultsController != nil)
{
return _fetchedResultsController;
}
sTCAppDelegate *appDelegate =[[UIApplication sharedApplication] delegate];
NSManagedObjectContext *context =[appDelegate managedObjectContext];
NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
NSEntityDescription *entity = [NSEntityDescription entityForName:@"TargetData" inManagedObjectContext:context];
[fetchRequest setEntity:entity];
[fetchRequest setFetchBatchSize:0];
NSSortDescriptor *sortDescriptor = [[NSSortDescriptor alloc] initWithKey:@"timeStamp" ascending:NO];
NSArray *sortDescriptors = [NSArray arrayWithObjects:sortDescriptor, nil];
[fetchRequest setSortDescriptors:sortDescriptors];
NSFetchedResultsController *aFetchedRequestsController = [[NSFetchedResultsController alloc] initWithFetchRequest:fetchRequest managedObjectContext:context sectionNameKeyPath:nil cacheName:@"Master"];
aFetchedRequestsController.delegate = self;
self.fetchedResultsController = aFetchedRequestsController;
NSError *error = nil;
if (![self.fetchedResultsController performFetch:&error])
{
NSLog(@"Unresolved error %@, %@", error, [error userInfo]);
abort();
}
return _fetchedResultsController;
}
- (void)controllerWillChangeContent:(NSFetchedResultsController *)controller {
[self.tableView beginUpdates];
}
- (void)controller:(NSFetchedResultsController *)controller didChangeSection:(id <NSFetchedResultsSectionInfo>)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)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)controllerDidChangeContent:(NSFetchedResultsController *)controller {
[self.tableView endUpdates];
}
- (IBAction)mainMenu:(id)sender {
[self.navigationController popToRootViewControllerAnimated:YES];
}
所以是的,我正在使用TableViewController实现中的方法。
编辑2
我通常在我的iPhone上运行我的应用程序来测试它,因为我可以在我的设备中使用相机。要查看控制台可能对我的问题说些什么,我将一些图像添加到模拟器并在模拟器上运行。这次,在添加带有文本的照片后,打开TableViewController,然后添加另一张照片,在尝试再次打开TableViewController后,我收到了一个巨大的崩溃错误报告。
以下是错误的终止部分:
2014-01-13 13:09:38.759 Target Tracker [25124:70b] ***由于未捕获的异常'NSInternalInconsistencyException'而终止app,原因:'CoreData:FATAL ERROR:段信息的持久缓存不匹配目前的配置。您已经非法改变了NSFetchedResultsController的获取请求,其谓词或其排序描述符,而没有禁用缓存或使用+ deleteCacheWithName:'
任何线索是什么意思?
分辨
问题是当我运行TableViewController时,我正在缓存FetchResults。当我向模型添加另一个实体并尝试返回一个新的fetchResult时,它与返回了一个关键CoreData错误的缓存版本不匹配。我没有看到它是一个错误,因为我最初没有在模拟器中运行应用程序,而是在我的实际设备上。一旦我在模拟器中运行它,我就能看到这个错误。
简而言之 - 我初始化NSFetchedResultsController时需要将“cacheName”设置为nil
NSFetchedResultsController *aFetchedRequestsController = [[NSFetchedResultsController alloc] initWithFetchRequest:fetchRequest managedObjectContext:context sectionNameKeyPath:nil cacheName:nil];
有关详细信息,请参阅此帖子:NSFetchedResultsController crashing on performFetch: when using a cache
答案 0 :(得分:1)
问题是当我运行TableViewController时,我正在缓存FetchResults。当我向模型添加另一个实体并尝试返回一个新的fetchResult时,它与返回了一个关键CoreData错误的缓存版本不匹配。我没有看到它是一个错误,因为我最初没有在模拟器中运行应用程序,而是在我的实际设备上。一旦我在模拟器中运行它,我就能看到这个错误。
简而言之 - 我初始化NSFetchedResultsController时需要将“cacheName”设置为nil
NSFetchedResultsController *aFetchedRequestsController = [[NSFetchedResultsController alloc] initWithFetchRequest:fetchRequest managedObjectContext:context sectionNameKeyPath:nil cacheName:nil];
有关详细信息,请参阅此帖子:NSFetchedResultsController crashing on performFetch: when using a cache
答案 1 :(得分:0)
您确定在向其添加对象后保存上下文吗?
插入对象后,请调用
- (BOOL)save:(NSError **)error;
答案 2 :(得分:0)
NSFetchedResultsController在收到保存上下文通知之前不会更新。这通常在您调用方法时执行:
[yourManagedObjectContext save:&error]
当获取的结果控制器收到更新时,会对其委托执行一些调用,请参阅名为NSFetchedResultsControllerDelegate的文档,并实现所有更新tableview的方法。这是正确的方法,您也可以只实现一种方法来查看是否有效:
- (void)controllerDidChangeContent:(NSFetchedResultsController *)controller
{
// In the simplest, most efficient, case, reload the table view.
[self.tableView reloadData];
}
答案 3 :(得分:0)
听起来你没有实现NSFetchedResultsController
委托方法。也许会显示一些代码UITableViewController
?
好的,你的代码看起来不错;非常好。
所以明显的,简单的可能性已经出来了。下一步是将一些断点(或日志)放入-saveTarget:
,-fetchedResultsController
和委托方法中,并确保一切都在触发。
使用您提供的代码,您应该看到更新。这暗示了没有被解雇的事情。