Я целый день рвал на себе волосы из-за ошибки «Не могу найти модель для исходного магазина».Вот ответ от Learner2010 для googlers:
Хеш модели вашей базы данных sqlite ДОЛЖЕН соответствовать одной из мам или мам, созданных вашей xcdatamodel при создании приложения.Вы можете увидеть хеши в momd's VersionInfo.plist в комплекте встроенного приложения.Ниже приведен код для поиска хэша модели вашей базы данных.
Так что если вы измените свой xcdatamodel вместо создания новой версии в Xcode-> Editor-> Add Model Version ... тогда вашхеш модели будет другим, и addPersistentStoreWithType не сможет использовать вашу старую базу данных, которая использовала старую модель.Вот почему возникает ошибка «Не удается найти модель для хранилища исходного кода».
Что еще хуже, база данных sqlite хранится в чем-то вроде "/ private / var / mobile / Library/ Мобильные документы / YOU_APP_ID / Data.nosync / YOUR_DB.sqlite ", и это может остаться, даже если вы удалите приложение с устройства и переустановите его!Таким образом, вы будете думать, что с вашим кодом что-то не так, когда на самом деле у вас просто устаревшая база данных, которую нужно удалить.Обычно это происходит во время отладки, поэтому в любом случае в нем нет реальных данных.
Поэтому правильный рабочий процесс, позволяющий выполнять миграции в будущем, - это создание модели, запуск приложения для построения базы данных,а затем создавать новые версии модели в любое время, когда вам нужно внести изменения.Все будет "просто работать", если вы оставите изменения незначительными.Затем, когда вы будете готовы выпустить свое приложение, выберите окончательную модель и удалите остальные.Затем удалите вашу базу данных из "/ private / var / mobile / Library / Mobile Documents".Затем в будущих выпусках включите все модели из предыдущих выпусков вместе с вашей новейшей моделью (если она изменилась), и пользователи смогут мигрировать каждый раз.
Вот мой код на данный момент,Важная строка:
[fileManager removeItemAtPath:iCloudData error:&error];
Но она используется только во время отладки для удаления вашей старой базы данных.Вот производственный код в AppDelegate.m:
- (NSManagedObjectModel *)managedObjectModel
{
if (__managedObjectModel != nil)
{
return __managedObjectModel;
}
//NSURL *modelURL = [[NSBundle mainBundle] URLForResource:@"Model" withExtension:@"momd"];
//__managedObjectModel = [[NSManagedObjectModel alloc] initWithContentsOfURL:modelURL];
//NSArray *testArray = [[NSBundle mainBundle] URLsForResourcesWithExtension:@"momd"subdirectory:nil];
NSString *path = [[NSBundle mainBundle] pathForResource:@"Model" ofType:@"momd"];
if( !path ) path = [[NSBundle mainBundle] pathForResource:@"Model" ofType:@"mom"];
NSURL *modelURL = [NSURL fileURLWithPath:path];
__managedObjectModel = [[NSManagedObjectModel alloc] initWithContentsOfURL:modelURL];
//__managedObjectModel = [NSManagedObjectModel mergedModelFromBundles:nil];
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 = @"RW6RS7HS69.com.zsculpt.soaktest";
// ** Note: if you adapt this code for your own use, you should change this variable:
NSString *dataFileName = @"mydailysoak.sqlite";
// ** Note: For basic usage you shouldn't need to change anything else
NSString *iCloudDataDirectoryName = @"Data.nosync";
NSString *iCloudLogsDirectoryName = @"Logs";
NSFileManager *fileManager = [NSFileManager defaultManager];
NSURL *localStore = [[self applicationDocumentsDirectory] URLByAppendingPathComponent:dataFileName];
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];
NSError *error;
[psc addPersistentStoreWithType:NSSQLiteStoreType
configuration:nil
URL:[NSURL fileURLWithPath:iCloudData]
options:options
error:&error];
if( error )
{
NSLog(@"Error adding persistent store %@, %@", error, [error userInfo]);
// comment in this line while debugging if get "Can't find model for source store" error in addPersistentStoreWithType.
// it means the sqlite database doesn't match the new model and needs to be created from scratch.
// this happens if you change the xcdatamodel instead of creating a new one under Xcode->Editor->Add Model Version...
// CoreData can only automatically migrate if there is a new model version (it can't migrate if the model simply changes, because it can't see the difference between the two models).
// be sure to back up the database if needed, because all data will be lost.
//[fileManager removeItemAtPath:iCloudData error:&error];
/*// this is another way to verify the hashes for the database's model to make sure they match one of the entries in the momd directory's VersionInfo.plist
NSDictionary *sourceMetadata = [NSPersistentStoreCoordinator metadataForPersistentStoreOfType:NSSQLiteStoreType URL:[NSURL fileURLWithPath:iCloudData] error:&error];
if( !sourceMetadata )
NSLog(@"sourceMetadata is nil");
else
NSLog(@"sourceMetadata is %@", sourceMetadata);*/
}
[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];
NSError *error;
[psc addPersistentStoreWithType:NSSQLiteStoreType
configuration:nil
URL:localStore
options:options
error:nil];
if( error )
NSLog(@"Error adding persistent store %@, %@", error, [error userInfo]);
[psc unlock];
}
dispatch_async(dispatch_get_main_queue(), ^{
[[NSNotificationCenter defaultCenter] postNotificationName:@"SomethingChanged" object:self userInfo:nil];
});
});
return __persistentStoreCoordinator;
}