使用 iCloud 时使用 NSFetchedResultsController 的表开始为空
Posted
技术标签:
【中文标题】使用 iCloud 时使用 NSFetchedResultsController 的表开始为空【英文标题】:Table using NSFetchedResultsController starts empty when using iCloud 【发布时间】:2012-10-29 18:03:56 【问题描述】:我的应用程序设置为使用 iCloud 的核心数据,但是当它启动时,显示数据的 UITableView 是空的,需要一点时间来填充数据。有没有办法让它立即显示数据,就好像它没有集成 iCloud 一样?
- (NSManagedObjectContext *)managedObjectContext
if (managedObjectContext != nil)
return managedObjectContext;
NSPersistentStoreCoordinator *coordinator = [self persistentStoreCoordinator];
if (coordinator != nil)
NSManagedObjectContext* moc = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSMainQueueConcurrencyType];
[moc performBlockAndWait:^
[moc setPersistentStoreCoordinator: coordinator];
[[NSNotificationCenter defaultCenter]addObserver:self selector:@selector(mergeChangesFrom_iCloud:) name:NSPersistentStoreDidImportUbiquitousContentChangesNotification object:coordinator];
];
managedObjectContext = moc;
managedObjectContext.mergePolicy = [[NSMergePolicy alloc]
initWithMergeType:NSMergeByPropertyObjectTrumpMergePolicyType];
return managedObjectContext;
- (void)mergeChangesFrom_iCloud:(NSNotification *)notification
NSLog(@"Merging in changes from iCloud...");
NSManagedObjectContext* moc = [self managedObjectContext];
[moc performBlock:^
[moc mergeChangesFromContextDidSaveNotification:notification];
NSNotification* refreshNotification = [NSNotification notificationWithName:@"SomethingChanged"
object:self
userInfo:[notification userInfo]];
[[NSNotificationCenter defaultCenter] postNotification:refreshNotification];
];
- (NSManagedObjectModel *)managedObjectModel
if (managedObjectModel != nil)
return managedObjectModel;
NSString *modelPath = [[NSBundle mainBundle] pathForResource:@"EntryDatabase" ofType:@"momd"];
NSURL *modelURL = [NSURL fileURLWithPath:modelPath];
managedObjectModel = [[NSManagedObjectModel alloc] initWithContentsOfURL:modelURL];
return managedObjectModel;
- (NSPersistentStoreCoordinator *)persistentStoreCoordinator
if((persistentStoreCoordinator != nil))
return persistentStoreCoordinator;
persistentStoreCoordinator = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel: [self managedObjectModel]];
NSPersistentStoreCoordinator *psc = persistentStoreCoordinator;
// Set up iCloud in another thread:
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^
// ** Note: if you adapt this code for your own use, you MUST change this variable:
NSString *iCloudEnabledAppID = @"IDRemovedFrom***";
// ** Note: if you adapt this code for your own use, you should change this variable:
NSString *dataFileName = @"CoreDataStore.sqlite";
// ** Note: For basic usage you shouldn't need to change anything else
NSString *iCloudDataDirectoryName = @"Data.nosync";
NSString *iCloudLogsDirectoryName = @"Logs";
NSFileManager *fileManager = [NSFileManager defaultManager];
NSString *storePath = [[self applicationDocumentsDirectory] stringByAppendingPathComponent:dataFileName];
NSURL *localStore = [NSURL fileURLWithPath:storePath];
NSURL *iCloud = [fileManager URLForUbiquityContainerIdentifier:nil];
if (iCloud)
NSLog(@"iCloud is working");
NSURL *iCloudLogsPath = [NSURL fileURLWithPath:[[iCloud path] stringByAppendingPathComponent:iCloudLogsDirectoryName]];
NSLog(@"iCloudEnabledAppID = %@",iCloudEnabledAppID);
NSLog(@"dataFileName = %@", dataFileName);
NSLog(@"iCloudDataDirectoryName = %@", iCloudDataDirectoryName);
NSLog(@"iCloudLogsDirectoryName = %@", iCloudLogsDirectoryName);
NSLog(@"iCloud = %@", iCloud);
NSLog(@"iCloudLogsPath = %@", iCloudLogsPath);
if([fileManager fileExistsAtPath:[[iCloud path] stringByAppendingPathComponent:iCloudDataDirectoryName]] == NO)
NSError *fileSystemError;
[fileManager createDirectoryAtPath:[[iCloud path] stringByAppendingPathComponent:iCloudDataDirectoryName]
withIntermediateDirectories:YES
attributes:nil
error:&fileSystemError];
if(fileSystemError != nil)
NSLog(@"Error creating database directory %@", fileSystemError);
NSString *iCloudData = [[[iCloud path]
stringByAppendingPathComponent:iCloudDataDirectoryName]
stringByAppendingPathComponent:dataFileName];
NSLog(@"iCloudData = %@", iCloudData);
NSMutableDictionary *options = [NSMutableDictionary dictionary];
[options setObject:[NSNumber numberWithBool:YES] forKey:NSMigratePersistentStoresAutomaticallyOption];
[options setObject:[NSNumber numberWithBool:YES] forKey:NSInferMappingModelAutomaticallyOption];
[options setObject:iCloudEnabledAppID forKey:NSPersistentStoreUbiquitousContentNameKey];
[options setObject:iCloudLogsPath forKey:NSPersistentStoreUbiquitousContentURLKey];
[psc lock];
[psc addPersistentStoreWithType:NSSQLiteStoreType
configuration:nil
URL:[NSURL fileURLWithPath:iCloudData]
options:options
error:nil];
[psc unlock];
else
NSLog(@"iCloud is NOT working - using a local store");
NSMutableDictionary *options = [NSMutableDictionary dictionary];
[options setObject:[NSNumber numberWithBool:YES] forKey:NSMigratePersistentStoresAutomaticallyOption];
[options setObject:[NSNumber numberWithBool:YES] forKey:NSInferMappingModelAutomaticallyOption];
[psc lock];
[psc addPersistentStoreWithType:NSSQLiteStoreType
configuration:nil
URL:localStore
options:options
error:nil];
[psc unlock];
dispatch_async(dispatch_get_main_queue(), ^
[[NSNotificationCenter defaultCenter] postNotificationName:@"SomethingChanged" object:self userInfo:nil];
);
);
return persistentStoreCoordinator;
- (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:@"Entry" inManagedObjectContext:[AppDelegate applicationDelegate].managedObjectContext];
[fetchRequest setEntity:entity];
// Set the batch size to a suitable number.
[fetchRequest setFetchBatchSize:20];
// Sort using the timeStamp property..
NSSortDescriptor *sortDescriptor = [[NSSortDescriptor alloc] initWithKey:@"creationDate" ascending:NO];
NSArray *sortDescriptors = [[NSArray alloc] initWithObjects:sortDescriptor, nil];
[fetchRequest setSortDescriptors:sortDescriptors];
// Use the sectionIdentifier property to group into sections.
NSFetchedResultsController *aFetchedResultsController = [[NSFetchedResultsController alloc] initWithFetchRequest:fetchRequest managedObjectContext:[AppDelegate applicationDelegate].managedObjectContext sectionNameKeyPath:@"sectionIdentifier" cacheName:@"Root"];
aFetchedResultsController.delegate = self;
self.fetchedResultsController = aFetchedResultsController;
self.fetchedResultsController.delegate = self;
return _fetchedResultsController;
【问题讨论】:
【参考方案1】:一种可能的解决方案是为您的包创建一个预填充的 .sqlite 文件,然后在创建持久存储协调器之前将其复制到 Documents 目录
【讨论】:
以上是关于使用 iCloud 时使用 NSFetchedResultsController 的表开始为空的主要内容,如果未能解决你的问题,请参考以下文章
禁用 iCloud 时是不是可以使用 NSMetadataQuery?
使用 Core Data 和 iCloud 添加持久存储时涉及 PFUbiquityPeer 的异常
使用 CloudKit/iCloud 时 Apple Store 构建被拒绝
使用 setUbiquitous 为 UIDocument 文件关闭 iCloud 同步时出错(LibrarianErrorDomain 错误 2)