以下是我要做的简化版本:
我有一个使用UITabBarController作为根控制器的应用程序。 在其中两个选项卡中,我有一个包含自定义UITableViewController的UINavigationController。
其中一个Tableviews用于显示“精选”项目,另一个用于显示“用户”项目。
第一个的API端点是:/ api / items / featured 另一个端点是:/ api / items / user
我在AppDelegate.m中完成设置所有内容的整个过程:
// Configure the object manager
RKObjectManager *objectManager = [RKObjectManager managerWithBaseURL:[NSURL URLWithString:API_SERVER]];
objectManager.managedObjectStore = managedObjectStore;
[RKObjectManager setSharedManager:objectManager];
RKEntityMapping *entityMapping = [RKEntityMapping mappingForEntityForName:@"Item" inManagedObjectStore:managedObjectStore];
[entityMapping addAttributeMappingsFromDictionary:@{
@"id": @"itemID",
@"type": @"type",
@"created_at": @"created_at":
@"field1": @"field1"}];
// User Descriptor
RKResponseDescriptor *userDescriptor = [RKResponseDescriptor responseDescriptorWithMapping:entityMapping pathPattern:@"/api/items/user" keyPath:nil statusCodes:RKStatusCodeIndexSetForClass(RKStatusCodeClassSuccessful)];
[objectManager addResponseDescriptor:userDescriptor];
// Featured Listing Decriptor
RKResponseDescriptor *featuredDescriptor = [RKResponseDescriptor responseDescriptorWithMapping:entityMapping pathPattern:@"/api/items/featured" keyPath:nil statusCodes:RKStatusCodeIndexSetForClass(RKStatusCodeClassSuccessful)];
[objectManager addResponseDescriptor:responseDescriptor];
然后在TableViewControls中我有以下内容(在第二个tableview控制器中用'features'代替'featured')
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
[self loadItems];
}
- (void)loadItems {
[[RKObjectManager sharedManager] getObjectsAtPath:@"/api/items/featured" parameters:nil
success:^(RKObjectRequestOperation *operation, RKMappingResult *mappingResult) {
self.lastupdate = [[NSDate alloc] init];
}
failure:^(RKObjectRequestOperation *operation, NSError *error) {
UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:@"An Error Has Occurred" message:[error localizedDescription] delegate:nil cancelButtonTitle:@"OK" otherButtonTitles:nil];
[alertView show];
}];
}
- (NSFetchedResultsController *)fetchedResultsController {
if (_fetchedResultsController != nil) {
return _fetchedResultsController;
}
RKManagedObjectStore *managedObjectStore = [RKManagedObjectStore defaultStore];
self.managedObjectContext = managedObjectStore.mainQueueManagedObjectContext;
NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
// Edit the entity name as appropriate.
NSEntityDescription *entity = [NSEntityDescription entityForName:@"Item" inManagedObjectContext:self.managedObjectContext];
[fetchRequest setEntity:entity];
// Set the batch size to a suitable number.
[fetchRequest setFetchBatchSize:20];
// Edit the sort key as appropriate.
NSSortDescriptor *sortDescriptor = [[NSSortDescriptor alloc] initWithKey:@"created_at" ascending:NO];
NSArray *sortDescriptors = @[sortDescriptor];
[fetchRequest setSortDescriptors:sortDescriptors];
// Set predicate to only get Featured Listings
NSPredicate *predicate = [NSPredicate predicateWithFormat: @"type like 'featured'"];
[fetchRequest setPredicate:predicate];
// Edit the section name key path and cache name if appropriate.
// nil for section name key path means "no sections".
NSFetchedResultsController *aFetchedResultsController = [[NSFetchedResultsController alloc] initWithFetchRequest:fetchRequest managedObjectContext:self.managedObjectContext sectionNameKeyPath:nil cacheName:@"Master"];
aFetchedResultsController.delegate = self;
self.fetchedResultsController = aFetchedResultsController;
NSError *error = nil;
if (![self.fetchedResultsController performFetch:&error]) {
// Replace this implementation with code to handle the error appropriately.
// abort() causes the application to generate a crash log and terminate. You should not use this function in a shipping application, although it may be useful during development.
NSLog(@"Unresolved error %@, %@", error, [error userInfo]);
abort();
}
return _fetchedResultsController;
}
现在这一切都适用于第一个标签(目前它返回8个项目,类型='精选',显示在表格中)。
当我切换到第二个标签时出现问题。它目前只返回1个type ='user'的项目,它崩溃了:
CoreData:错误:严重的应用程序错误。在Core Data更改处理期间捕获到异常。这通常是NSManagedObjectContextObjectsDidChangeNotification的观察者中的错误。 * - [__ NSArrayM objectAtIndex:]:索引3超出带有userInfo的空数组的边界(null)
如果我在“用户”标签上省略谓词,那么“精选”标签工作正常,“用户”标签会在其表格中显示“特色”项目,其中“用户”项位于顶部。< / p>
由于两个tableview控件的代码是相同的,除了'user'和'featured'之外,我对问题所在的位置感到茫然。
答案 0 :(得分:1)
创建和配置提取的结果控制器时,请勿使用缓存。目前他们都使用@"Master"
的缓存,这将导致他们尝试共享不合适的信息,因为获取请求不同。
答案 1 :(得分:1)
您是否在UITableViewController上实现了NSFetchedResultsControllerDelegate更改方法?我在使用RestKit / RKGist作为模板时发现了类似的错误,在删除了这些更改方法后,将控制器作为委托删除,此错误消失了。这对我有用,因为我不想以这种方式收到有关更改的通知:我从结果的重新获取中分离出fetchedResultsController的getter,并在相应的RKObjectRequestOperation的成功块中调用了refetching。希望有所帮助!
修改
在我的情况下,我实际上在一个UITableViewController中使用了两个NSFetchedResultsController:
在我的.h界面
@property (strong, nonatomic) NSFetchedResultsController *fetchedResultsOneController;
@property (strong, nonatomic) NSFetchedResultsController *fetchedResultsTwoController;
在.m实现中:
每个的相应getter,调用刻出的重新提取
- (NSFetchedResultsController *)fetchedResultsOneController
{
if (_fetchedResultsOneController != nil) {
return _fetchedResultsOneController;
}
[self refetchResultsOneController];
return _fetchedResultsOneController;
}
重新获取只包含构建获取请求,实体描述,排序和获取控制器的其余逻辑,如:
- (void) refetchResultsOneController
{
NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
NSEntityDescription *entity = ...;
[fetchRequest setEntity:entity];
// set predicate for venue name
NSPredicate *predicate = [NSPredicate predicateWithFormat: ....];
[fetchRequest setPredicate:predicate];
[fetchRequest setFetchBatchSize:200];
NSSortDescriptor *distanceDescriptor = [[NSSortDescriptor alloc] initWithKey:...];
NSArray *sortDescriptors = @[distanceDescriptor];
[fetchRequest setSortDescriptors:sortDescriptors];
NSFetchedResultsController *aFetchedResultsController = [[NSFetchedResultsController alloc] initWithFetchRequest:fetchRequest managedObjectContext:self.managedObjectContext sectionNameKeyPath:nil cacheName:@"SomeUniqueName"];
self.fetchedResultsOneController = aFetchedResultsController;
NSError *error = nil;
if (![self.fetchedResultsOneController performFetch:&error]) {
.. error handle...;
}
}
请注意,refetchers是不同的;不同的实体和不同的nspredicates,但相同的ManagedObjectContext。
并且在objectmanager动作的成功块中调用refetch,对于resultsOne它的一个简单:
[objectManager getObjectsAtPath:[NSString stringWithFormat:@"...the path for results one...", venueId] parameters:queryParams
success:^(RKObjectRequestOperation *operation, RKMappingResult *mappingResult) {
[self refetchResultsOneController];
[self.tableView reloadData];
}
failure:^(RKObjectRequestOperation *operation, NSError *error) {
NSLog(@"Error: %@", [error localizedDescription]);
}];
这适用于我在一个UITableViewController中使用两个NSFetchResultsController。注意我不允许用户操作来编辑/删除fetchController中的对象(没有双向通信) - 但我只对那里的数据读取感兴趣,而且只有成功刷新才能启动它远程服务器。
希望这有帮助!