在 iOS 上,replaceItemAtURL 失败且没有错误,但在 OSX 上工作正常

发布于 2024-10-15 15:35:17 字数 2425 浏览 2 评论 0原文

我正在为基于 CoreData 的应用程序实现手动触发的迁移过程,迁移成功完成后,我尝试使用 replaceItemAtURL:withItemAtURL:backupItemName 将迁移的数据库移回到原始数据库的顶部:options:resultingItemURL:error:

问题是,在 iOS 上,我所做的任何事情都不会让这个方法返回 YES,但是它也不会将任何内容放入错误指针中以让您查看出了什么问题。

我在其他地方读过一些东西(例如 http://www.cocoabuilder.com/archive/cocoa/287790-nsdoc-magic-file-watcher-ruins-core-data-migration.html) 表示不关闭所有 CoreData 对象(例如 NSMigrationManager、NSManagedObjectModel 等)在尝试替换之前可能是原因,但事实并非如此。我什至实现了一些完全不涉及 CoreData DB 的两个文件创建和交换的东西,以验证 CoreData 的东西与它没有任何关系。

然后我注意到 官方文档表明 newitemURL 应该位于适合临时文件的目录中。我假设这意味着 URLForDirectory:inDomain:propertyForURL:create:error: 使用 NSItemReplacementDirectory 作为搜索路径返回的目录。

那也没用!我最终又转而使用单独的操作来实现替换逻辑,但这是非原子的、不安全的以及所有这些不好的东西。

是否有人拥有在 iOS 上运行的工作代码片段,该代码片段要么从调用 replaceItemAtURL 返回 YES,要么实际上将错误信息放入错误指针中?

非常感谢任何帮助。

编辑 - 下面包含测试代码。它在主线程上的 application:didFinishLaunchingWithOptions: 中运行。

NSFileManager *fm = [[NSFileManager alloc] init];
NSError *err = nil;
NSURL *docDir = [NSURL fileURLWithPath:[self applicationDocumentsDirectory]];

NSURL *tmpDir = [fm URLForDirectory:NSItemReplacementDirectory
                           inDomain:NSUserDomainMask
                  appropriateForURL:docDir
                             create:NO
                              error:&err];

NSURL *u1 = [docDir URLByAppendingPathComponent:@"f1"];
NSURL *u2 = [tmpDir URLByAppendingPathComponent:@"f2"];
NSURL *repl = nil;

[fm createFileAtPath:[u1 path]
            contents:[[NSString stringWithString:@"Hello"]
                      dataUsingEncoding:NSUTF8StringEncoding]
          attributes:nil];

[fm createFileAtPath:[u2 path]
            contents:[[NSString stringWithString:@"World"]        
                      dataUsingEncoding:NSUTF8StringEncoding]
          attributes:nil];

BOOL test = [fm replaceItemAtURL:u1 withItemAtURL:u2 backupItemName:@"f1backup"
                         options:0 resultingItemURL:&repl error:&err];

// At this point GDB shows test to be NO but error is still nil

I'm implementing a manually-triggered migration process for a CoreData-based app, and after the migration completes successfully, I'm trying to move the migrated DB back over the top of the original one using replaceItemAtURL:withItemAtURL:backupItemName:options:resultingItemURL:error:.

The problem is that on iOS, nothing I do will make this method return YES, however it also never puts anything into the error pointer to allow you to see what's going wrong.

I'd read things elsewhere (e.g. http://www.cocoabuilder.com/archive/cocoa/287790-nsdoc-magic-file-watcher-ruins-core-data-migration.html) indicating that not shutting down all the CoreData objects (e.g. NSMigrationManager, NSManagedObjectModel etc) before attempting the replace might be the cause, but that wasn't it. I even implemented a little two file create-and-swap thing that didn't involve CoreData DBs at all to verify that the CoreData stuff didn't have anything to do with it.

I then noticed in the official documentation that the newitemURL is supposed to be in a directory deemed appropriate for temporary files. I assumed that that meant a directory returned by URLForDirectory:inDomain:appropriateForURL:create:error: using NSItemReplacementDirectory as the search path.

That didn't work either! I ended up falling back to implementing the replacement logic using separate operations, but this is non-atomic and unsafe and all that bad stuff.

Does anyone have a working snippet of code that runs on iOS that either return YES from a call to replaceItemAtURL or actually puts error information into the error pointer?

Any help much appreciated.

EDIT - Test code included below. This runs in application:didFinishLaunchingWithOptions: on the main thread.

NSFileManager *fm = [[NSFileManager alloc] init];
NSError *err = nil;
NSURL *docDir = [NSURL fileURLWithPath:[self applicationDocumentsDirectory]];

NSURL *tmpDir = [fm URLForDirectory:NSItemReplacementDirectory
                           inDomain:NSUserDomainMask
                  appropriateForURL:docDir
                             create:NO
                              error:&err];

NSURL *u1 = [docDir URLByAppendingPathComponent:@"f1"];
NSURL *u2 = [tmpDir URLByAppendingPathComponent:@"f2"];
NSURL *repl = nil;

[fm createFileAtPath:[u1 path]
            contents:[[NSString stringWithString:@"Hello"]
                      dataUsingEncoding:NSUTF8StringEncoding]
          attributes:nil];

[fm createFileAtPath:[u2 path]
            contents:[[NSString stringWithString:@"World"]        
                      dataUsingEncoding:NSUTF8StringEncoding]
          attributes:nil];

BOOL test = [fm replaceItemAtURL:u1 withItemAtURL:u2 backupItemName:@"f1backup"
                         options:0 resultingItemURL:&repl error:&err];

// At this point GDB shows test to be NO but error is still nil

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

乱世争霸 2024-10-22 15:35:17

我在 iOS 上使用 URL 的所有 NSFileManager 方法都遇到了问题。但是,所有使用 Path 的方法都有效。因此,我认为您应该使用 removeItemAtPath:error:copyItemAtPath:toURL:error: 来实现此目的。

希望有帮助

I have experienced issues with all the NSFileManager methods using an URL on iOS. However, all the methods using Path work. So I think you should use removeItemAtPath:error:and copyItemAtPath:toURL:error: for that purpose.

Hope it helps

北城挽邺 2024-10-22 15:35:17

在mac文件系统中不区分大小写,但在IOS中则如此。即使一个位置不能有两个名称相同但大小写不同的文件,路径也是区分大小写的。因此,如果文件具有 .JPEG 并且在您的代码中传递带有 .jpeg 的链接,它将失败。
您的情况可能并非如此,但只是分享什么,

尽管奇怪的是它应该给您错误。

In mac file system is not case sensitive, but in IOS it. Even though you cant have two files with same name but with different case at one location, the path is case sensitive. So if file is has .JPEG and in your code you are passing link with .jpeg it will fail.
It may not be the case with you but just what to share

Although strangely it should give you error.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文