4

我的基于 Core Data 文档的应用程序(仅限 10.5)的数据模型位于框架中,因此使用 Core Data 映射模型的自动模式升级似乎不起作用。当 Core Data 机器不在应用程序的主包中时,它们似乎找不到合适的数据模型或映射模型。因此,我没有使用自动迁移,而是 configurePersistentStoreCoordinatorForURL:ofType:...在我的 NSPersistenDocument子类(下面的代码)。我将持久存储迁移到一个临时文件,然后在迁移成功时覆盖现有文件。然后该文档显示错误消息“自从您打开或保存此文档的文件已被另一个应用程序更改”。当我尝试保存时。正如此列表中的其他人所指出的,这是由于我在“背后”修改了文档的文件。我尝试更新文档的文件修改日期,如下所示,但随后出现错误对话框,显示消息“无法确定文档“test.ovproj”的位置。” 当我尝试保存时。我不太确定这个错误的原因,但是将一个不必要的消息(在这种情况下)换成另一个并不是我想要的。

任何人都可以提供一些指导吗?有没有办法手动升级文档持久存储的架构而不触发其中一个(在这种情况下是不必要的)警告?

用于升级我的子类中的数据存储的代码 -configurePersistentStoreCoordinatorForURL:ofType:...

if(upgradeNeeded) {
           NSManagedObjectModel *sourceModel = [NSManagedObjectModel mergedModelFromBundles:VUIModelBundles() orStoreMetadata:meta];

           if(sourceModel == nil) {
               *error = [NSError errorWithDomain:VUIErrorDomainn ode:VUICoreDataErrorCode localizedReason:BWLocalizedString(@"Unable to find original data model for project.")];
               return NO;
           }

           NSManagedObjectModel *destinationModel = [self managedObjectModel];

           NSMigrationManager *migrationManager = [[NSMigrationManager alloc] initWithSourceModel:sourceModel destinationModel:destinationModel];
           NSMappingModel *mappingModel = [NSMappingModel mappingModelFromBundles:VUIModelBundles() forSourceModel:sourceModel destinationModel:destinationModel];
           if(mappingModel == nil) {
               *error = [NSError errorWithDomain:VUIErrorDomain code:VUICoreDataErrorCode localizedReason:BWLocalizedString(@"Unable to find mapping model to convert project to most recent project format.")];
               return NO;
           }

           @try {
               //move file to backup
               NSAssert([url isFileURL], @"store url is not a file URL");

               NSString *tmpPath = [NSString tempFilePath];
               id storeType = [meta objectForKey:NSStoreTypeKey];
               if(![migrationManager migrateStoreFromURL:url
                                                    type:storeType
                                                 options:storeOptions
                                        withMappingModel:mappingModel
                                       toDestinationURL:[NSURLfileURLWithPath:tmpPath]
                                         destinationType:storeType
                                      destinationOptions:storeOptions
                                                   error:error]) {

                   return NO;
               } else {
                   //replace old with new
                   if(![[NSFileManager defaultManager] removeItemAtPath:[url path] error:error] ||
                      ![[NSFileManager defaultManager] moveItemAtPath:tmpPath toPath:[url path] error:error]) {
                       return NO;
                   }

                   // update document file modification date to prevent warning (#292)
                   NSDate *newModificationDate = [[[NSFileManager defaultManager] fileAttributesAtPath:[url path] traverseLink:NO] bjectForKey:NSFileModificationDate];
                   [self setFileModificationDate:newModificationDate];
               }
           }
           @finally {
               [migrationManager release];
           }
       }
   }

   return [super configurePersistentStoreCoordinatorForURL:url ofType:fileType modelConfiguration:configuration storeOptions:storeOptions error:error];
4

3 回答 3

1

我没有遇到过这种特殊情况,但我有一些猜测。首先,当您想要切换文件时,不要使用 -removeItemAtPath: 和 -moveItemAtPath: ,而是使用 FSExchangeObjects() 函数。NSDocument 使用 FSRefs 来跟踪文件,除非您使用 FSExchangeObjects(),否则它会意识到它正在查看一个完全不同的文件。

其次,您可以通过覆盖 -managedObjectModel 手动设置文档的托管对象模型,特别是使用 +mergedModelFromBundles: 方法从框架加载模型。根据文档,默认情况下它应该合并主包和所有链接框架中的任何模型,因此这只对动态加载的包是必需的。不知道为什么这对你不起作用,但我没有尝试过。要找出要搜索的捆绑包,NSBundle 的 +bundleForClass: 方法是您的朋友。

于 2008-12-19T16:43:11.980 回答
1

当心 FSExchangeObjects()!它不支持所有卷类型,请参阅 bSupportsFSExchangeObjects。我正在寻找自己的替代品。选项似乎是 MoreFilesX 的 FSExchangeObjectsCompat 或 10.5 的 FSReplaceObjects()。

于 2009-11-19T00:27:40.073 回答
0

10 年后...我遇到了同样的问题,并且使用 NSDocument 的新 API,您可以在迁移后使用更新文件的新日期更新文档的 fileModificationDate

migrate()
if let newModificationDate = try? NSFileManager.defaultManager().attributesOfItemAtPath(url.path!)[NSFileModificationDate] as? NSDate {
    self.fileModificationDate = newModificationDate
}

之后你可以打电话super.configurePersistentStoreCoordinatorForURL...

readFromURL:ofType 这是因为 NSDocument 甚至在调用See Document Initialization Message Flow之前就设置了文件修改日期

于 2018-02-22T15:24:50.547 回答