Restkit/CoreData - 更新实体的属性不会更新 UITableView
Posted
技术标签:
【中文标题】Restkit/CoreData - 更新实体的属性不会更新 UITableView【英文标题】:Restkit/CoreData - Updating an entity's attribute does not update UITableView 【发布时间】:2014-12-17 22:59:13 【问题描述】:我有一个实体Country
,其中包含一个属性downloaded
,其默认值为0,并且未被RestKit 映射。我希望能够根据这个下载的属性将我的 tableView 分组。一切都按预期工作,直到我尝试自己以编程方式更改下载的值。代码如下:
我试图设置值的地方 - 我的上下文是通过 AppDelegate 传递给控制器的 mainQueueManagedObjectContext
。
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
[tableView deselectRowAtIndexPath:indexPath animated:YES];
Country *country = [self.fetchedResultsController objectAtIndexPath:indexPath];
[FGDataCalls downloadFieldGuide:country.countryId];
//Set up to get the thing you want to update
NSFetchRequest * request = [[NSFetchRequest alloc] init];
[request setEntity:[NSEntityDescription entityForName:@"Country" inManagedObjectContext:self.managedObjectContext]];
[request setPredicate:[NSPredicate predicateWithFormat:@"countryId = %@", country.countryId]];
NSError *error = nil;
country = [[self.managedObjectContext executeFetchRequest:request error:&error] lastObject];
if (error)
NSLog(@"Error getting the country from core data: %@", error);
country.downloaded = 1;
error = nil;
if (![self.managedObjectContext save:&error])
NSLog(@"Saving changes to country failed: %@", error);
FetchedResultsController:
- (NSFetchedResultsController *)fetchedResultsController
if (_fetchedResultsController != nil)
return _fetchedResultsController;
/*
Set up the fetched results controller.
*/
// Create the fetch request for the entity.
NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
// Edit the entity name as appropriate.
NSEntityDescription *entity = [NSEntityDescription entityForName:@"Country" inManagedObjectContext:self.managedObjectContext];
[fetchRequest setEntity:entity];
// Set the batch size to a suitable number.
[fetchRequest setFetchBatchSize:20];
// Sort using the name property.
NSSortDescriptor *sortDownloaded = [[NSSortDescriptor alloc] initWithKey:@"downloaded" ascending:NO];
NSSortDescriptor *sortName = [[NSSortDescriptor alloc] initWithKey:@"name" ascending:YES];
[fetchRequest setSortDescriptors:@[sortDownloaded, sortName]];
// Use the sectionIdentifier property to group into sections.
_fetchedResultsController = [[NSFetchedResultsController alloc] initWithFetchRequest:fetchRequest managedObjectContext:self.managedObjectContext sectionNameKeyPath:@"downloaded" cacheName:nil];
_fetchedResultsController.delegate = self;
self.fetchedResultsController = _fetchedResultsController;
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;
初始化 Restkit:
//Enable RestKit logging
//RKLogConfigureByName("RestKit/ObjectMapping", RKLogLevelInfo);
//RKLogConfigureByName("RestKit/CoreData", RKLogLevelTrace);
//RKLogConfigureByName("RestKit/Network", RKLogLevelTrace);
// Initialize RestKit
RKObjectManager *objectManager = [RKObjectManager managerWithBaseURL:[NSURL URLWithString:BaseURLString]];
// Initialize managed object store
NSError *error = nil;
NSURL *modelURL = [NSURL fileURLWithPath:[[NSBundle mainBundle] pathForResource:@"FGDataModel" ofType:@"momd"]];
NSManagedObjectModel *managedObjectModel = [[NSManagedObjectModel alloc] initWithContentsOfURL:modelURL];
RKManagedObjectStore *managedObjectStore = [[RKManagedObjectStore alloc] initWithManagedObjectModel:managedObjectModel];
BOOL success = RKEnsureDirectoryExistsAtPath(RKApplicationDataDirectory(), &error);
if (!success)
RKLogError(@"Failed to create Application Data Directory at path '%@': %@", RKApplicationDataDirectory(), error);
objectManager.managedObjectStore = managedObjectStore;
NSString *path = [RKApplicationDataDirectory() stringByAppendingPathComponent:@"FGDataModel.sqlite"];
NSPersistentStore *persistentStore = [managedObjectStore addSQLitePersistentStoreAtPath:path fromSeedDatabaseAtPath:nil withConfiguration:nil options:nil error:&error];
if (! persistentStore)
RKLogError(@"Failed adding persistent store at path '%@': %@", path, error);
// Configure a managed object cache to ensure we do not create duplicate objects
managedObjectStore.managedObjectCache = [[RKInMemoryManagedObjectCache alloc] initWithManagedObjectContext:managedObjectStore.persistentStoreManagedObjectContext];
[managedObjectStore createManagedObjectContexts];
// Set the default store shared instance
[RKManagedObjectStore setDefaultStore:managedObjectStore];
// Setup our object mappings
[FGDataCalls setupObjectMappings:managedObjectStore withObjectManager:objectManager];
// Save the MOC
AppDelegate *appDelegate = [[UIApplication sharedApplication]delegate];
appDelegate.managedObjectContext = managedObjectStore.mainQueueManagedObjectContext;
此时我已经尝试以多种不同的方式保存上下文,包括块,但我还没有让 fetchedResultsController 识别更新,甚至调用controllerWillChangeContent:
或controllerDidChangeContent:
。我已经使用 MOC 的 deleteObject:
方法成功删除了一行,所以我的上下文处于正确的状态。在设置下载的属性后,我什至可以从我的 fetchedResultsController 中获取对象并查看它是否正确,但表永远不会更新。此外,在我更改属性后强制重新加载表不会产生任何结果。我知道这是一个具体案例,但希望其他人也遇到过同样的问题,或者可以看出我哪里出错了。
谢谢!
【问题讨论】:
“已下载”属性是NSNumber
还是标量类型?从 .xcdatamodel 生成 NSManagedObject 时,您是否勾选了“使用原始数据类型的标量属性”?
请出示您的 FRC 委托方法!
我可以添加它们,但它们目前都只是 Apple 的样板方法。当我对 FRC 进行更改时,它们不会被调用
哦,哇,Michal 非常感谢。我不知道我不能使用标量类型,Core Data 也没有表明由于我试图保存 NSInteger 而失败。更改为NSNumber
,一切正常。
【参考方案1】:
保存时不应该这样做
error = nil;
if (![self.managedObjectContext save:&error])
NSLog(@"Saving changes to country failed: %@", error);
你应该这样做
error = nil;
if (![self.managedObjectContext saveToPersistentStore:&error])
NSLog(@"Saving changes to country failed: %@", error);
也就是说,假设 FRC 连接到相同的上下文,那么它应该在保存更改之前看到更改。您也没有显示您的 FRC 委托方法,因此可能存在问题。
【讨论】:
我也尝试过,但结果相同。我的 FRC 委托方法此时都只是样板的 Apple 方法,但是当我更改 FRC 中的对象时,它们都不会被访问。 那我看不出有什么明显的错误。您是否自动生成了托管对象子类? 在上面的cmets中解决了。我不知道 Core Data 只适用于NSNumber
- 我现在永远不会忘记它。以上是关于Restkit/CoreData - 更新实体的属性不会更新 UITableView的主要内容,如果未能解决你的问题,请参考以下文章
我可以防止 RestKit+CoreData 覆盖本地实体更改吗?
RestKit / Core Data:远程删除的实体不会从 Core Data 中删除
RestKit + CoreData,理解 RKManagedObjectRequestOperation
RestKit CoreData 0.20.3 - 映射完成后保存 MOC 之前的额外检查
Restkit + Coredata - NSFetchedResultsControllerDelegate 回调不会单独为更新操作触发