Первое обновление приложения, потеря данных пользователя (хранилась в каталоге Documents) - программирование
Подтвердить что ты не робот

Первое обновление приложения, потеря данных пользователя (хранилась в каталоге Documents)

Мое первое обновление для приложения прошло вчера вечером, и я получил жалобу на то, что обновление вызвало исчезновение пользовательских данных (некоторые из них). Я смог воспроизвести проблему, но не могу понять, почему.

В папке "Документы" я сохранил один ключевой файл, который сообщает мне "название" всех файлов пользователя и их файлов (полный путь). Затем все пользовательские файлы также находятся в каталоге Documents.

Когда происходит обновление, файл ключей все еще существует (по крайней мере, я думаю, это потому, что данные отображаются на первом экране приложения - приложения полностью завершают работу и перезапускают после обновления, верно?), но когда пользователь пытается перейти к фактическим файлам, данных нет, и любые новые данные, которые пользователь вводит, никогда не сохраняются.

Он действует точно так же, как при отладке, когда я случайно использовал недопустимое имя файла (с неправильными символами в нем) - он никогда не сохранялся. Но с обновлением эти файлы были сохранены правильно в старой версии, но как-то не работают в новой версии.

Это мое первое приложение и мое первое обновление, и я здесь совсем не понимаю. Я вытащил приложение из продажи на данный момент (не знал, что вы не можете просто вернуться к старой версии! Yikes!) И глубоко оценит любые идеи о том, где/как искать проблему и как писать ХОРОШЕЕ обновление, которое не потеряет данные. (Пока все, что я нашел, это "сохранить данные в каталоге" Документы ", что я уже делал.)

У меня есть оригинальное приложение, сохраненное в его собственном проекте, и я могу вернуться и снова работать с этим. Я скопировал весь этот каталог, когда начал работать над обновлением, и я задаюсь вопросом, может ли это как-то быть проблемой? Я изменил имя каталога, в котором хранятся все файлы XCode, и использовал функцию Project > Rename. Может ли это иметь такой эффект?

Приложение (как оригинал, так и обновление) работает на 4.2 и выше, если это имеет значение.

Решение:

Я считаю, что я понял эту проблему. Как я уже говорил в начале моего вопроса, я сохранял ПОЛНУЮ ПУТЬ файлов пользователя в моих файлах ключей. По-видимому, после обновления не гарантируется, что полный путь не будет таким же (я уверен, что это где-то где-то зарегистрировано, но я не сталкивался с ним).

Итак, пользовательские файлы HAD были перенесены в новый каталог Documents, но я искал их по старому абсолютному пути, то есть не в моей песочнице.

Исправлено, поместив цикл в приложение didFinishLaunching, чтобы вытащить нарушительный файл файловых путей (THAT, я всегда искал локально, и он все еще работал) и отрубал их только до файлаNAMES. Путь к документам должен быть найден и добавлен программно всякий раз, когда выполняются операции с файлами.

Для меня это было действительно полезно для меня, что нет способа вернуться к предыдущему двоичному файлу в магазине, потому что повторная установка исходной версии не устранила бы проблему пользователя, но я бы поверила, что она, по крайней мере, изначально. Я бы хотел, чтобы был способ отклонить ОБНОВЛЕНИЯ, но все же разрешил новые покупки (так как проблема не повлияла на новые покупки). Вероятно, это не достаточно распространенная ситуация, чтобы гарантировать это.

4b9b3361

Ответ 1

Просто пролить немного света на это для интернет-прохожих. Да, ОП ответил на свой вопрос в самом конце. Вы никогда не должны хранить абсолютные URL-адреса для файлов в каталоге документов, и это может привести к потере данных. Это связано с тем, что при обновлении приложения, изменяя свою версию # в файле .plist, iOS создает новый каталог для этого приложения с другим шестнадцатеричным именем. Теперь ваш абсолютный URL-адрес ссылается на неправильное местоположение и не вернет правильный файл.

Вы можете увидеть это на своем собственном компьютере, прежде чем развертывать его на устройстве, перейдя к

~/Library/Поддержка приложений/Симулятор iPhone/* ios_version */Приложения/

Там вы увидите папки с именами вроде:

6AA4B05C-8A38-4469-B7BE-5EA7E9712510 CB43C5F3-D720-49C3-87D4-EBE93FFD428B

Внутри этих папок будет стандартный макет файловой системы для приложений iOS. то есть.

Документы Библиотека TMP YourApp.app

Переходя по всему URL-адресу, вы увидите что-то вроде

~/Library/Поддержка приложений /iPhone Simulator/* ios_version */Приложения/6AA4B05C-8A38-4469-B7BE-5EA7E9712510/Documents/MyVeryImportantUserData.txt

Однако при обновлении приложения новый URL-адрес приложения будет выглядеть следующим образом:

~/Library/Поддержка приложений /iPhone Simulator/* ios_version */Приложения/CB43C5F3-D720-49C3-87D4-EBE93FFD428B/Documents/MyVeryImportantUserData.txt

который пуст.

Вместо этого вы всегда должны делать динамическую ссылку, сохраняя только путь к файлу после того, как вы получили префикс пути к файлу каталога документов.

/**
 Returns the path to the application Documents directory.
 */
- (NSString *)applicationDocumentsDirectory {
    return [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) lastObject];
}

На исходный плакат вы могли бы сохранить ваши потерянные данные пользователей, выпустив новое обновление, в котором вы изменили свой код, чтобы получить абсолютный URL-адрес и обрезать все через часть документов в строке. Затем вы можете префикс пути к файлу с соответствующим URL-адресом каталога, и приложение обнаружило бы данные.

Ответ 2

Оба вопросника и первый ответ были полезны для выяснения того, что именно происходит.

Поэтому, основываясь на своих наблюдениях, я понял, что было (что, кажется,) переименование папок в пути, ведущем к папке "Документы". Это привело меня к решению, в котором я сохраняю только файлы имен файлов и создаю класс утилиты для захвата строки fullPath current, которая была сохранена и теперь хранится в текущая папка "Документы" после обновления приложения:

#import "StringUtils.h"

@implementation StringUtils

+ (NSString *)getFullDocumentUrl:(NSString *)fileName
{
    return [NSString stringWithFormat:@"%@/%@",[self applicationDocumentsDirectory],fileName];
}

+ (NSString *)applicationDocumentsDirectory
{
    return [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) lastObject];
}

@end

Ответ 3

Я столкнулся с той же проблемой. Ниже приведен пример кода для исправления ваших имен файлов путем итерации через файлы в каталоге документов и замены информации о пути файла, оставляя имена файлов. Перед выполнением последней строки, чтобы изменить имена файлов, я рекомендовал бы использовать NSLog, чтобы убедиться, что это именно то, что вы хотите в своем обновленном имени.

    NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
    NSString *documentsPath = [paths objectAtIndex:0]; //Get the docs directory
    NSFileManager *fm = [NSFileManager defaultManager];
    NSArray *filenames = [fm contentsOfDirectoryAtPath:documentsPath error:nil];

    //Match on the filepath leading up to docs directory
    NSRegularExpression *regex = [NSRegularExpression regularExpressionWithPattern:@"^/\\S*Documents/"
                                                                           options:NSRegularExpressionCaseInsensitive
                                                                             error:nil];
    for (NSString *fileName in filenames)
    {
        NSRange fullLength = NSMakeRange(0, [fileName length]);
        //swap out the prepended directory structure with an empty string
        NSString *updatedFileName = [regex stringByReplacingMatchesInString:fileName
                                                                    options:0
                                                                      range:fullLength
                                                               withTemplate:@""];
        NSString *currentName = [NSString stringWithFormat:@"%@/%@",documentsPath,fileName];
        NSString *updatedName = [NSString stringWithFormat:@"%@/%@",documentsPath,updatedFileName];
        [fm moveItemAtPath:currentName toPath:updatedName error:nil];
    }