代码之家  ›  专栏  ›  技术社区  ›  Barry Wark

在没有“文档已更改”警告的情况下手动迁移核心数据架构?

  •  4
  • Barry Wark  · 技术社区  · 16 年前

    我的核心数据文档应用程序(仅10.5)的数据模型位于 框架,因此使用核心数据映射自动升级模式 模型似乎不起作用。核心数据机器 没有找到合适的数据模型或映射模型 不在应用程序的主包中。所以,不用自动 迁移,我正在手动运行迁移 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];
    
    3 回复  |  直到 7 年前
        1
  •  1
  •   Boaz Stuller    16 年前

    我没有遇到这种特殊情况,但我有一些猜测。首先,不要使用-removeitematpath:和-moveitematpath:切换文件,而是使用fsexchangeobjects()函数。nsdocument使用fsrefs跟踪文件,除非使用fsexchangeobjects(),否则会发现它正在查看完全不同的文件。

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

        2
  •  1
  •   Anan    15 年前

    当心fsExchangeObjects()!它不支持所有卷类型,请参阅bsupportsfsexchangeobjects。我正在找一个替代品。选项似乎是MorefilesX的fsExchangeObjectsCompat或10.5的fsReplaceObjects()。

        3
  •  0
  •   AMTourky    7 年前

    10年后… 我遇到了同样的问题,使用nsdocument的新api,您可以在执行迁移后使用更新文件的新日期更新文档的filemodificationdate。

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

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

    这是因为nsdocument甚至在调用 readFromURL:ofType Document Initialization Message Flow