Core Data 和 NSFRC 显示条目,但在每次启动时都不会持久存在,并且出现 Key-Value 编码错误
Core Data and NSFRC showing entries but not persisting through every launch and a Key-Value Coding Error
我正在构建一个非常简单的应用程序,允许用户在应用程序中浏览有关特定主题的传单和视频。我带来的功能之一是能够将传单或视频标记为收藏夹。
该应用程序 UITabBar
有 5 个选项卡,每个选项卡由 UITableViewController
表示。当用户点击以按住选项卡中的单元格时,它会将其标记为 "starred" 并使用 Core Data
和 NSFetchedResultsController
,目的是让该条目出现在已加星标中标签。
这是我的简单核心数据模型:
因此,当用户在 4 个选项卡中的任何一个中点击并按住一个单元格时,这就是代码 I 运行:
- (void)swipeableTableViewCell:(SWTableViewCell *)cell didTriggerRightUtilityButtonWithIndex:(NSInteger)index
{
switch (index) {
case 0:
{
NSIndexPath *indexPath = [self.tableView indexPathForCell:cell];
CustomLeafletVideoTableViewCell *cell = (CustomLeafletVideoTableViewCell*)[self.tableView cellForRowAtIndexPath:indexPath];
NSString *cellTitle = cell.customCellLabel.text;
[self moreButtonPressed:cellTitle];
[cell hideUtilityButtonsAnimated:YES];
break;
}
default:
break;
}
}
- (void)cellPressed:(NSString *)passedString
{
NSManagedObjectContext *context = [self managedObjectContext];
Item *item = [NSEntityDescription insertNewObjectForEntityForName:@"Item" inManagedObjectContext:context];
Videos *videos = [NSEntityDescription insertNewObjectForEntityForName:@"Videos" inManagedObjectContext:context];
videos.title = passedString;
item.video = videos;
NSLog(@"Passed String = %@", videos.title);
}
我创建了一个 FavouritesTableViewController
class,这里是主要代码:
- (NSManagedObjectContext *)managedObjectContext
{
NSManagedObjectContext *context = nil;
id delegate = [[UIApplication sharedApplication] delegate];
if ([delegate performSelector:@selector(managedObjectContext)])
{
context = [delegate managedObjectContext];
}
return context;
}
- (NSFetchedResultsController *)fetchedResultsController
{
NSManagedObjectContext *managedObjectContext = [self managedObjectContext];
if (_fetchedResultsController != nil)
{
return _fetchedResultsController;
}
NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
NSEntityDescription *entity = [NSEntityDescription entityForName:@"Videos" inManagedObjectContext:managedObjectContext];
fetchRequest.entity = entity;
NSPredicate *d = [NSPredicate predicateWithFormat:@"items.video.@count !=0"];
[fetchRequest setPredicate:d];
NSSortDescriptor *sort = [[NSSortDescriptor alloc] initWithKey:@"title" ascending:NO];
fetchRequest.sortDescriptors = [NSArray arrayWithObject:sort];
fetchRequest.fetchBatchSize = 20;
NSFetchedResultsController *theFetchedResultsController = [[NSFetchedResultsController alloc] initWithFetchRequest:fetchRequest managedObjectContext:managedObjectContext sectionNameKeyPath:nil cacheName:nil];
self.fetchedResultsController = theFetchedResultsController;
_fetchedResultsController.delegate = self;
return _fetchedResultsController;
}
- (void)viewDidLoad {
[super viewDidLoad];
NSError *error;
if (![[self fetchedResultsController] performFetch:&error])
{
//exit(-1);
}
self.favouritesTableView.dataSource = self;
self.favouritesTableView.delegate = self;
}
- (void)viewWillAppear:(BOOL)animated
{
[super viewWillAppear:animated];
[self.favouritesTableView reloadData];
}
#pragma mark - Table view data source
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
id sectionInfo = [[_fetchedResultsController sections] objectAtIndex:section];
return [sectionInfo numberOfObjects];
}
#pragma mark Cell Configuration
- (void)configureCell:(UITableViewCell *)cell atIndexPath:(NSIndexPath *)indexPath
{
CustomLeafletVideoTableViewCell *customCell = (CustomLeafletVideoTableViewCell *)cell;
Videos *videos = [self.fetchedResultsController objectAtIndexPath:indexPath];
NSLog(@"What is the video . title %@", videos.title);
customCell.customCellLabel.text = videos.title;
//
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = @"FavouritesCell";
CustomLeafletVideoTableViewCell *cell = (CustomLeafletVideoTableViewCell *)[tableView dequeueReusableCellWithIdentifier:CellIdentifier];
[self configureCell:cell atIndexPath:indexPath];
return cell;
}
#pragma mark NSFetchedResultsControllerDelegate Methods
- (void)controllerWillChangeContent:(NSFetchedResultsController *)controller
{
[self.tableView beginUpdates];
}
- (void)controller:(NSFetchedResultsController *)controller didChangeObject:(id)anObject atIndexPath:(NSIndexPath *)indexPath forChangeType:(NSFetchedResultsChangeType)type newIndexPath:(NSIndexPath *)newIndexPath
{
// The boiler plate code for the NSFetchedResultsControllerDelegate
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;
default:
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];
}
问题
我的问题似乎源于 NSFetchedResultsController
。在那种方法中,如果我将它与谓词保持原样,当我点击以将单元格保留在另一个选项卡上时,应用程序崩溃并显示:
Terminating app due to uncaught exception 'NSUnknownKeyException', reason: '[<Videos 0x7ffb48d0b910> valueForUndefinedKey:]: the entity Videos is not key value coding-compliant for the key "@count".'
如果我删除谓词行:
// NSPredicate *d = [NSPredicate predicateWithFormat:@"items.video.@count !=0"];
// [fetchRequest setPredicate:d];
当我点击以按住一个单元格时,它会将其标记为收藏,然后当我转到“收藏夹”选项卡时,条目就在那里。但是,如果我再次启动该应用程序,“收藏夹”选项卡中的条目就会消失。
我不太确定这里发生了什么。本质上,“收藏夹”选项卡是一个用于存储用户在其他选项卡中加星标的项目的地方。我是否需要谓词?如果不需要,为什么每次启动时数据都不会持久存在?
应用设置时选择了 Core Data
,因此 AppDelegate
已正确设置。
任何关于这方面的指导将不胜感激。
video
属性 和 Item
是一对一的关系。基本上它是一个指向对象(或 nil)的指针。你不能算,它不是对象的集合
所以你的关键路径 items.video.@count
尤其是 video.@count
没有意义,因此崩溃。
如果要检查给定 Item
是否存在 video
,请使用 @"items.video != nil"
。
此外,您可能应该遵循约定,对对象名称使用单数(Leaflet
和 Video
),对一对一关系使用单数(item
而不是 items
).
我正在构建一个非常简单的应用程序,允许用户在应用程序中浏览有关特定主题的传单和视频。我带来的功能之一是能够将传单或视频标记为收藏夹。
该应用程序 UITabBar
有 5 个选项卡,每个选项卡由 UITableViewController
表示。当用户点击以按住选项卡中的单元格时,它会将其标记为 "starred" 并使用 Core Data
和 NSFetchedResultsController
,目的是让该条目出现在已加星标中标签。
这是我的简单核心数据模型:
因此,当用户在 4 个选项卡中的任何一个中点击并按住一个单元格时,这就是代码 I 运行:
- (void)swipeableTableViewCell:(SWTableViewCell *)cell didTriggerRightUtilityButtonWithIndex:(NSInteger)index
{
switch (index) {
case 0:
{
NSIndexPath *indexPath = [self.tableView indexPathForCell:cell];
CustomLeafletVideoTableViewCell *cell = (CustomLeafletVideoTableViewCell*)[self.tableView cellForRowAtIndexPath:indexPath];
NSString *cellTitle = cell.customCellLabel.text;
[self moreButtonPressed:cellTitle];
[cell hideUtilityButtonsAnimated:YES];
break;
}
default:
break;
}
}
- (void)cellPressed:(NSString *)passedString
{
NSManagedObjectContext *context = [self managedObjectContext];
Item *item = [NSEntityDescription insertNewObjectForEntityForName:@"Item" inManagedObjectContext:context];
Videos *videos = [NSEntityDescription insertNewObjectForEntityForName:@"Videos" inManagedObjectContext:context];
videos.title = passedString;
item.video = videos;
NSLog(@"Passed String = %@", videos.title);
}
我创建了一个 FavouritesTableViewController
class,这里是主要代码:
- (NSManagedObjectContext *)managedObjectContext
{
NSManagedObjectContext *context = nil;
id delegate = [[UIApplication sharedApplication] delegate];
if ([delegate performSelector:@selector(managedObjectContext)])
{
context = [delegate managedObjectContext];
}
return context;
}
- (NSFetchedResultsController *)fetchedResultsController
{
NSManagedObjectContext *managedObjectContext = [self managedObjectContext];
if (_fetchedResultsController != nil)
{
return _fetchedResultsController;
}
NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
NSEntityDescription *entity = [NSEntityDescription entityForName:@"Videos" inManagedObjectContext:managedObjectContext];
fetchRequest.entity = entity;
NSPredicate *d = [NSPredicate predicateWithFormat:@"items.video.@count !=0"];
[fetchRequest setPredicate:d];
NSSortDescriptor *sort = [[NSSortDescriptor alloc] initWithKey:@"title" ascending:NO];
fetchRequest.sortDescriptors = [NSArray arrayWithObject:sort];
fetchRequest.fetchBatchSize = 20;
NSFetchedResultsController *theFetchedResultsController = [[NSFetchedResultsController alloc] initWithFetchRequest:fetchRequest managedObjectContext:managedObjectContext sectionNameKeyPath:nil cacheName:nil];
self.fetchedResultsController = theFetchedResultsController;
_fetchedResultsController.delegate = self;
return _fetchedResultsController;
}
- (void)viewDidLoad {
[super viewDidLoad];
NSError *error;
if (![[self fetchedResultsController] performFetch:&error])
{
//exit(-1);
}
self.favouritesTableView.dataSource = self;
self.favouritesTableView.delegate = self;
}
- (void)viewWillAppear:(BOOL)animated
{
[super viewWillAppear:animated];
[self.favouritesTableView reloadData];
}
#pragma mark - Table view data source
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
id sectionInfo = [[_fetchedResultsController sections] objectAtIndex:section];
return [sectionInfo numberOfObjects];
}
#pragma mark Cell Configuration
- (void)configureCell:(UITableViewCell *)cell atIndexPath:(NSIndexPath *)indexPath
{
CustomLeafletVideoTableViewCell *customCell = (CustomLeafletVideoTableViewCell *)cell;
Videos *videos = [self.fetchedResultsController objectAtIndexPath:indexPath];
NSLog(@"What is the video . title %@", videos.title);
customCell.customCellLabel.text = videos.title;
//
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = @"FavouritesCell";
CustomLeafletVideoTableViewCell *cell = (CustomLeafletVideoTableViewCell *)[tableView dequeueReusableCellWithIdentifier:CellIdentifier];
[self configureCell:cell atIndexPath:indexPath];
return cell;
}
#pragma mark NSFetchedResultsControllerDelegate Methods
- (void)controllerWillChangeContent:(NSFetchedResultsController *)controller
{
[self.tableView beginUpdates];
}
- (void)controller:(NSFetchedResultsController *)controller didChangeObject:(id)anObject atIndexPath:(NSIndexPath *)indexPath forChangeType:(NSFetchedResultsChangeType)type newIndexPath:(NSIndexPath *)newIndexPath
{
// The boiler plate code for the NSFetchedResultsControllerDelegate
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;
default:
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];
}
问题
我的问题似乎源于 NSFetchedResultsController
。在那种方法中,如果我将它与谓词保持原样,当我点击以将单元格保留在另一个选项卡上时,应用程序崩溃并显示:
Terminating app due to uncaught exception 'NSUnknownKeyException', reason: '[<Videos 0x7ffb48d0b910> valueForUndefinedKey:]: the entity Videos is not key value coding-compliant for the key "@count".'
如果我删除谓词行:
// NSPredicate *d = [NSPredicate predicateWithFormat:@"items.video.@count !=0"];
// [fetchRequest setPredicate:d];
当我点击以按住一个单元格时,它会将其标记为收藏,然后当我转到“收藏夹”选项卡时,条目就在那里。但是,如果我再次启动该应用程序,“收藏夹”选项卡中的条目就会消失。
我不太确定这里发生了什么。本质上,“收藏夹”选项卡是一个用于存储用户在其他选项卡中加星标的项目的地方。我是否需要谓词?如果不需要,为什么每次启动时数据都不会持久存在?
应用设置时选择了 Core Data
,因此 AppDelegate
已正确设置。
任何关于这方面的指导将不胜感激。
video
属性 和 Item
是一对一的关系。基本上它是一个指向对象(或 nil)的指针。你不能算,它不是对象的集合
所以你的关键路径 items.video.@count
尤其是 video.@count
没有意义,因此崩溃。
如果要检查给定 Item
是否存在 video
,请使用 @"items.video != nil"
。
此外,您可能应该遵循约定,对对象名称使用单数(Leaflet
和 Video
),对一对一关系使用单数(item
而不是 items
).