NSRangeException',原因:'*** -[__NSArrayI objectAtIndex:]: 索引 2 超出范围 [0 .. 1] CoreData 和 NSFRC 错误
NSRangeException', reason: '*** -[__NSArrayI objectAtIndex:]: index 2 beyond bounds [0 .. 1] error with CoreData and NSFRC
我有一个简单的应用程序,它有两个选项卡 UITabBarController
。第一个选项卡称为 Languages
,它包含应用程序中的硬编码语言列表。在 prepareForSegue
方法中,我通过 NSMutableArray
填充该语言的传单和视频列表,并将其成功传递给名为 LeafletsAndVideos
的新 UITableViewController
。有些语言有传单和视频,有些只有传单,传单在第 0 节,视频在第 1 节。
参考这个问题:,我在LeafetsAndVideos
中设置了使用"Favourting"个特定的单元格。通过使用 Core Data
,我将收藏的单元格的标题添加到 Core Data
模型中。我这样做的原因是因为第二个选项卡被称为 Favourites
,并且通过使用 NSFetchedResultsController
,我用 "Favourited" 中的所有单元格填充此 UITableView
。
那个公园真的很好。
现在的问题是,在 LeafletsAndVideos
UITableView
中,我收藏了一个单元格,它通过在 FavouritesTableViewController
,但如果我想取消收藏同一个单元格,我希望将其从 Favourites
选项卡中删除。
问题
问题是当我取消收藏一个单元格时,它只是再次添加到 Favourites
选项卡。
为了清楚起见,当我说 "Favourite" 时,假设我正在点击单元格 (didSelectCell
),所以当我再次点击它时,它取消收藏。
LeafletsAndTable
UITableView
没有引用 NSFRC
并且它实际上不需要一个,因为单元格由 NSMutableArray's
中的集合填充语言 UITableView
(我完全理解我可以只使用 Core Data
作为标题,但是在这个特定的设置中这很复杂 - Core Data
只是被用作检测收藏夹标题的机制细胞)。
在我的 LeafletAndVideo
UITableView
中,我在设置 Favourites
时有以下代码:
NSIndexPath *indexPath = [self.tableView indexPathForCell:cell];
CustomLeafletVideoTableViewCell *cell = (CustomLeafletVideoTableViewCell*)[self.tableView cellForRowAtIndexPath:indexPath];
NSString *cellTitle = cell.customCellLabel.text;
NSManagedObjectContext *context = [self managedObjectContext];
Favourites *favourites = [NSEntityDescription insertNewObjectForEntityForName:@"Favourites" inManagedObjectContext:context];
favourites.title = cellTitle;
NSString *key = [NSString stringWithFormat:@"%@_%ld_%ld", self.selectedLanguage, (long)indexPath.section, (long)indexPath.row];
if (self.favoritesDict[key] == nil) {
self.favoritesDict[key] = @(1);
} else {
[self.favoritesDict removeObjectForKey:key];
}
[[NSUserDefaults standardUserDefaults] setObject:self.favoritesDict forKey:@"favoritesDict"];
NSError *error = nil;
if (![context save:&error])
{
// Error
}
[cell hideUtilityButtonsAnimated:YES];
[self.tableView reloadRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationAutomatic];
问题
使用上面的代码,当取消收藏一个单元格时,它会再次添加到“收藏夹”选项卡(这很公平,因为我没有在这里进行任何删除操作)。
所以在该代码的 else 语句中,我尝试了一些东西。我从字典中删除了 object,但我也调用了 Favourites
选项卡和方法 completeFetchedResults
:
if (self.favoritesDict[key] == nil) {
self.favoritesDict[key] = @(1);
} else {
[self.favoritesDict removeObjectForKey:key];
FavouritesTableViewController *favTab = [[FavouritesTableViewController alloc] init];
[favTab completeFetchedResults];
[favTab moreButtonPressed:indexPath];
}
此方法只是调用 NSFRC
上的提取。
- (void)completeFetchedResults
{
NSError *error;
if (![[self fetchedResultsController] performFetch:&error])
{
//exit(-1);
}
}
然后我调用删除 object 的方法,方法是将 indexPath
:
传递给它
- (void)moreButtonPressed:(NSIndexPath *)indexPath
{
NSManagedObjectContext *context = [self managedObjectContext];
[self.managedObjectContext deleteObject:[self.fetchedResultsController objectAtIndexPath:indexPath]];
NSError *error = nil;
if (![context save:&error])
{
// Error
}
}
当我 运行 这个 select 一个单元格时,它会收藏它(如预期的那样)并添加到 Favourites
选项卡。当我再次 select 单元格(删除收藏夹)时,它因以下错误而崩溃:
'NSRangeException', reason: '*** -[__NSArrayI objectAtIndex:]: index 2 beyond bounds [0 .. 1]'
当我放置异常断点时,它在以下位置崩溃:
if (![context save:&error])
{
// Error
}
在moreButtonPressed
方法中。
我不太确定如何解决这个问题,但期望的效果是当我 select 单元格时,它收藏它(工作)并且当我再次 select 单元格时,它:
1) 从“收藏夹”选项卡中删除 object(不起作用)
任何指导将不胜感激。
堆栈跟踪更新
0 CoreFoundation 0x000000010c588f45 __exceptionPreprocess + 165
1 libobjc.A.dylib 0x000000010bc7adeb objc_exception_throw + 48
2 CoreFoundation 0x000000010c477b14 -[__NSArrayI objectAtIndex:] + 164
3 Street Parchar 0x000000010b5e8b37 -[FavouritesTableViewController moreButtonPressed:] + 151
4 Street Parchar 0x000000010b5f2386 -[LeafletsAndVideosTableViewController swipeableTableViewCell:didTriggerRightUtilityButtonWithIndex:] + 1158
5 Street Parchar 0x000000010b5e44d5 -[SWTableViewCell rightUtilityButtonHandler:] + 213
6 UIKit 0x000000010d1e194f _UIGestureRecognizerSendTargetActions + 153
7 UIKit 0x000000010d1ddfc1 _UIGestureRecognizerSendActions + 162
8 UIKit 0x000000010d1dbfbe -[UIGestureRecognizer _updateGestureWithEvent:buttonEvent:] + 843
9 UIKit 0x000000010d1e4283 ___UIGestureRecognizerUpdate_block_invoke898 + 79
10 UIKit 0x000000010d1e4121 _UIGestureRecognizerRemoveObjectsFromArrayAndApplyBlocks + 342
11 UIKit 0x000000010d1d1bdd _UIGestureRecognizerUpdate + 2634
12 UIKit 0x000000010cd6f9c0 -[UIWindow _sendGesturesForEvent:] + 1137
13 UIKit 0x000000010cd70bf6 -[UIWindow sendEvent:] + 849
14 UIKit 0x000000010cd202fa -[UIApplication sendEvent:] + 263
15 UIKit 0x000000010ccfaabf _UIApplicationHandleEventQueue + 6844
16 CoreFoundation 0x000000010c4b5011 __CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE0_PERFORM_FUNCTION__ + 17
17 CoreFoundation 0x000000010c4aaf3c __CFRunLoopDoSources0 + 556
18 CoreFoundation 0x000000010c4aa3f3 __CFRunLoopRun + 867
19 CoreFoundation 0x000000010c4a9e08 CFRunLoopRunSpecific + 488
20 GraphicsServices 0x0000000111165ad2 GSEventRunModal + 161
21 UIKit 0x000000010cd0030d UIApplicationMain + 171
22 Street Parchar 0x000000010b5dfedf main + 111
23 libdyld.dylib 0x00000001104ae92d start + 1
24 ??? 0x0000000000000001 0x0 + 1
)
libc++abi.dylib:以 NSException
类型的未捕获异常终止
更新 2
在FavouritesTab
中包含fetchedResultsController
- (NSFetchedResultsController *)fetchedResultsController
{
NSManagedObjectContext *managedObjectContext = [self managedObjectContext];
if (_fetchedResultsController != nil)
{
return _fetchedResultsController;
}
NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
NSEntityDescription *entity = [NSEntityDescription entityForName:@"Favourites" inManagedObjectContext:managedObjectContext];
fetchRequest.entity = entity;
NSPredicate *d = [NSPredicate predicateWithFormat:@"title != nil"];
[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;
}
问题是 FavouritesTableViewController
的新实例没有连接到 Interface Builder 中对应的 object。
您必须像此代码一样在 LeafletsAndVideos
控制器中执行所有与核心数据相关的任务
NSString *key = [NSString stringWithFormat:@"%@_%ld_%ld", self.selectedLanguage, (long)indexPath.section, (long)indexPath.row];
if (self.favoritesDict[key] == nil) {
self.favoritesDict[key] = @(1);
Favourites *favourites = [NSEntityDescription insertNewObjectForEntityForName:@"Favourites" inManagedObjectContext:context];
favourites.title = cellTitle;
}
else {
[self.favoritesDict removeObjectForKey:key];
NSError *error;
NSFetchRequest *request = [[NSFetchRequest alloc] init];
request.entity = [NSEntityDescription entityForName:@"Favourites" inManagedObjectContext: context];
request.predicate = [NSPredicate predicateWithFormat:@"title == %@", cellTitle];
NSArray *items = [context executeFetchRequest:request error:&error];
if (error == nil && items.count) {
NSManagedObject *managedObject = items[0];
[context deleteObject:managedObject];
}
}
当您切换到“收藏夹”选项卡并在 viewWillAppear
中执行提取时,数据将正确显示。
我有一个简单的应用程序,它有两个选项卡 UITabBarController
。第一个选项卡称为 Languages
,它包含应用程序中的硬编码语言列表。在 prepareForSegue
方法中,我通过 NSMutableArray
填充该语言的传单和视频列表,并将其成功传递给名为 LeafletsAndVideos
的新 UITableViewController
。有些语言有传单和视频,有些只有传单,传单在第 0 节,视频在第 1 节。
参考这个问题:LeafetsAndVideos
中设置了使用"Favourting"个特定的单元格。通过使用 Core Data
,我将收藏的单元格的标题添加到 Core Data
模型中。我这样做的原因是因为第二个选项卡被称为 Favourites
,并且通过使用 NSFetchedResultsController
,我用 "Favourited" 中的所有单元格填充此 UITableView
。
那个公园真的很好。
现在的问题是,在 LeafletsAndVideos
UITableView
中,我收藏了一个单元格,它通过在 FavouritesTableViewController
,但如果我想取消收藏同一个单元格,我希望将其从 Favourites
选项卡中删除。
问题
问题是当我取消收藏一个单元格时,它只是再次添加到 Favourites
选项卡。
为了清楚起见,当我说 "Favourite" 时,假设我正在点击单元格 (didSelectCell
),所以当我再次点击它时,它取消收藏。
LeafletsAndTable
UITableView
没有引用 NSFRC
并且它实际上不需要一个,因为单元格由 NSMutableArray's
中的集合填充语言 UITableView
(我完全理解我可以只使用 Core Data
作为标题,但是在这个特定的设置中这很复杂 - Core Data
只是被用作检测收藏夹标题的机制细胞)。
在我的 LeafletAndVideo
UITableView
中,我在设置 Favourites
时有以下代码:
NSIndexPath *indexPath = [self.tableView indexPathForCell:cell];
CustomLeafletVideoTableViewCell *cell = (CustomLeafletVideoTableViewCell*)[self.tableView cellForRowAtIndexPath:indexPath];
NSString *cellTitle = cell.customCellLabel.text;
NSManagedObjectContext *context = [self managedObjectContext];
Favourites *favourites = [NSEntityDescription insertNewObjectForEntityForName:@"Favourites" inManagedObjectContext:context];
favourites.title = cellTitle;
NSString *key = [NSString stringWithFormat:@"%@_%ld_%ld", self.selectedLanguage, (long)indexPath.section, (long)indexPath.row];
if (self.favoritesDict[key] == nil) {
self.favoritesDict[key] = @(1);
} else {
[self.favoritesDict removeObjectForKey:key];
}
[[NSUserDefaults standardUserDefaults] setObject:self.favoritesDict forKey:@"favoritesDict"];
NSError *error = nil;
if (![context save:&error])
{
// Error
}
[cell hideUtilityButtonsAnimated:YES];
[self.tableView reloadRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationAutomatic];
问题
使用上面的代码,当取消收藏一个单元格时,它会再次添加到“收藏夹”选项卡(这很公平,因为我没有在这里进行任何删除操作)。
所以在该代码的 else 语句中,我尝试了一些东西。我从字典中删除了 object,但我也调用了 Favourites
选项卡和方法 completeFetchedResults
:
if (self.favoritesDict[key] == nil) {
self.favoritesDict[key] = @(1);
} else {
[self.favoritesDict removeObjectForKey:key];
FavouritesTableViewController *favTab = [[FavouritesTableViewController alloc] init];
[favTab completeFetchedResults];
[favTab moreButtonPressed:indexPath];
}
此方法只是调用 NSFRC
上的提取。
- (void)completeFetchedResults
{
NSError *error;
if (![[self fetchedResultsController] performFetch:&error])
{
//exit(-1);
}
}
然后我调用删除 object 的方法,方法是将 indexPath
:
- (void)moreButtonPressed:(NSIndexPath *)indexPath
{
NSManagedObjectContext *context = [self managedObjectContext];
[self.managedObjectContext deleteObject:[self.fetchedResultsController objectAtIndexPath:indexPath]];
NSError *error = nil;
if (![context save:&error])
{
// Error
}
}
当我 运行 这个 select 一个单元格时,它会收藏它(如预期的那样)并添加到 Favourites
选项卡。当我再次 select 单元格(删除收藏夹)时,它因以下错误而崩溃:
'NSRangeException', reason: '*** -[__NSArrayI objectAtIndex:]: index 2 beyond bounds [0 .. 1]'
当我放置异常断点时,它在以下位置崩溃:
if (![context save:&error])
{
// Error
}
在moreButtonPressed
方法中。
我不太确定如何解决这个问题,但期望的效果是当我 select 单元格时,它收藏它(工作)并且当我再次 select 单元格时,它:
1) 从“收藏夹”选项卡中删除 object(不起作用)
任何指导将不胜感激。
堆栈跟踪更新
0 CoreFoundation 0x000000010c588f45 __exceptionPreprocess + 165
1 libobjc.A.dylib 0x000000010bc7adeb objc_exception_throw + 48
2 CoreFoundation 0x000000010c477b14 -[__NSArrayI objectAtIndex:] + 164
3 Street Parchar 0x000000010b5e8b37 -[FavouritesTableViewController moreButtonPressed:] + 151
4 Street Parchar 0x000000010b5f2386 -[LeafletsAndVideosTableViewController swipeableTableViewCell:didTriggerRightUtilityButtonWithIndex:] + 1158
5 Street Parchar 0x000000010b5e44d5 -[SWTableViewCell rightUtilityButtonHandler:] + 213
6 UIKit 0x000000010d1e194f _UIGestureRecognizerSendTargetActions + 153
7 UIKit 0x000000010d1ddfc1 _UIGestureRecognizerSendActions + 162
8 UIKit 0x000000010d1dbfbe -[UIGestureRecognizer _updateGestureWithEvent:buttonEvent:] + 843
9 UIKit 0x000000010d1e4283 ___UIGestureRecognizerUpdate_block_invoke898 + 79
10 UIKit 0x000000010d1e4121 _UIGestureRecognizerRemoveObjectsFromArrayAndApplyBlocks + 342
11 UIKit 0x000000010d1d1bdd _UIGestureRecognizerUpdate + 2634
12 UIKit 0x000000010cd6f9c0 -[UIWindow _sendGesturesForEvent:] + 1137
13 UIKit 0x000000010cd70bf6 -[UIWindow sendEvent:] + 849
14 UIKit 0x000000010cd202fa -[UIApplication sendEvent:] + 263
15 UIKit 0x000000010ccfaabf _UIApplicationHandleEventQueue + 6844
16 CoreFoundation 0x000000010c4b5011 __CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE0_PERFORM_FUNCTION__ + 17
17 CoreFoundation 0x000000010c4aaf3c __CFRunLoopDoSources0 + 556
18 CoreFoundation 0x000000010c4aa3f3 __CFRunLoopRun + 867
19 CoreFoundation 0x000000010c4a9e08 CFRunLoopRunSpecific + 488
20 GraphicsServices 0x0000000111165ad2 GSEventRunModal + 161
21 UIKit 0x000000010cd0030d UIApplicationMain + 171
22 Street Parchar 0x000000010b5dfedf main + 111
23 libdyld.dylib 0x00000001104ae92d start + 1
24 ??? 0x0000000000000001 0x0 + 1
) libc++abi.dylib:以 NSException
类型的未捕获异常终止更新 2
在FavouritesTab
fetchedResultsController
- (NSFetchedResultsController *)fetchedResultsController
{
NSManagedObjectContext *managedObjectContext = [self managedObjectContext];
if (_fetchedResultsController != nil)
{
return _fetchedResultsController;
}
NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
NSEntityDescription *entity = [NSEntityDescription entityForName:@"Favourites" inManagedObjectContext:managedObjectContext];
fetchRequest.entity = entity;
NSPredicate *d = [NSPredicate predicateWithFormat:@"title != nil"];
[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;
}
问题是 FavouritesTableViewController
的新实例没有连接到 Interface Builder 中对应的 object。
您必须像此代码一样在 LeafletsAndVideos
控制器中执行所有与核心数据相关的任务
NSString *key = [NSString stringWithFormat:@"%@_%ld_%ld", self.selectedLanguage, (long)indexPath.section, (long)indexPath.row];
if (self.favoritesDict[key] == nil) {
self.favoritesDict[key] = @(1);
Favourites *favourites = [NSEntityDescription insertNewObjectForEntityForName:@"Favourites" inManagedObjectContext:context];
favourites.title = cellTitle;
}
else {
[self.favoritesDict removeObjectForKey:key];
NSError *error;
NSFetchRequest *request = [[NSFetchRequest alloc] init];
request.entity = [NSEntityDescription entityForName:@"Favourites" inManagedObjectContext: context];
request.predicate = [NSPredicate predicateWithFormat:@"title == %@", cellTitle];
NSArray *items = [context executeFetchRequest:request error:&error];
if (error == nil && items.count) {
NSManagedObject *managedObject = items[0];
[context deleteObject:managedObject];
}
}
当您切换到“收藏夹”选项卡并在 viewWillAppear
中执行提取时,数据将正确显示。