replaceItemAtURL не работает без ошибок на iOS, но отлично работает на OSX

Я реализую запускаемый вручную процесс миграции для приложения на основе 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, чтобы убедиться, что материалы CoreData не имеют к этому никакого отношения.

Затем я заметил в официальный документации, что newitemURL должен находиться в каталоге, который считается подходящим для временных файлов. Я предположил, что это означает каталог, возвращенный URLForDirectory:inDomain:appropriateForURL:create:error: с использованием NSItemReplacementDirectory в качестве пути поиска.

Это тоже не сработало! В итоге я вернулся к реализации логики замены с использованием отдельных операций, но это не атомарно, небезопасно и все такое плохое.

Есть ли у кого-нибудь работающий фрагмент кода, работающий на iOS, который либо возвращает YES при вызове replaceItemAtURL, либо фактически помещает информацию об ошибке в указатель ошибки?

Любая помощь высоко ценится.

РЕДАКТИРОВАТЬ. Тестовый код приведен ниже. Это выполняется в 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

person glenc    schedule 04.02.2011    source источник
comment
Добавили код выше Джонатана - любой вклад приветствуется.   -  person glenc    schedule 06.02.2011
comment
Я сталкиваюсь с той же проблемой. Я попытался поместить создание файла, на который указывает newItemURL, в каталоги, соответствующие как NSTemporaryDirectory(), так и NSCachesDirectory, и он все еще терпит неудачу без каких-либо ошибок. Вам повезло?   -  person Tony    schedule 08.04.2011
comment
К сожалению нет. В итоге я просто работал над этим, реализовав его сам, что действительно отстой как решение.   -  person glenc    schedule 08.04.2011
comment
Может ли resultItemURL быть нулевым? В документах об этом не сказано.   -  person spstanley    schedule 09.04.2011
comment
@spstanley - спасибо за предложение, вы правы, документы не говорят, что resultingItemURL может быть нулевым, поэтому я изменил код, включив ненулевые значения как для него, так и для backupItemName, и все равно получаю тот же результат. Возвращаемое значение из вызова замены — НЕТ, но ошибка по-прежнему равна нулю. В основном все еще кажется сломанным! Тем не менее спасибо за предложение.   -  person glenc    schedule 11.04.2011
comment
Вы поняли это? Я тоже попадаю в это.   -  person Steven Fisher    schedule 12.05.2011
comment
К сожалению, нет - я все еще работаю со своей пользовательской логикой и вообще не использую replaceItemAtURL...   -  person glenc    schedule 12.05.2011
comment
Ваш пример кода на самом деле сломан и не работает так, как вы описываете. Я запустил этот код (скопировал/вставил в Xcode) на iPhone под управлением iOS 4.3.3; tmpDir равно нулю после вызова URLForDirectory:etc:, и в результате u2 также равно нулю, а вызов replaceItemAtURL:etc: приводит к сбою приложения. Что вы на самом деле делаете? Этот код не тот.   -  person Tom Harrington    schedule 23.06.2011
comment
Я был рад найти этот вопрос, но мне было грустно видеть, что ни у кого нет ответа. Я столкнулся с тем же самым: метод возвращает НЕТ, но не устанавливает ошибку, чтобы сказать мне, почему он не работает. Арх!   -  person Sixten Otto    schedule 19.08.2011
comment
Я запустил этот код на iOS 6, и он работает (возвращает YES). Так что это может быть ошибка, которая была устранена, начиная с iOS 4.   -  person Drew    schedule 25.01.2013
comment
Что не так с rename()?   -  person tc.    schedule 09.03.2013


Ответы (2)


У меня возникли проблемы со всеми методами NSFileManager с использованием URL-адреса в iOS. Однако все методы, использующие Path, работают. Поэтому я думаю, что вы должны использовать removeItemAtPath:error:и copyItemAtPath:toURL:error: для этой цели.

Надеюсь, поможет

person Fran Sevillano    schedule 07.09.2011

В файловой системе mac регистр не учитывается, а в IOS — нет. Несмотря на то, что у вас не может быть двух файлов с одинаковым именем, но с разным регистром в одном месте, путь чувствителен к регистру. Поэтому, если файл имеет .JPEG, а в вашем коде вы передаете ссылку с .jpeg, это не удастся. Это может быть не так с вами, но просто то, что поделиться

Хотя странно это должно дать вам ошибку.

person Atif Khan    schedule 20.02.2013