SQLite, iPhone и управление версиями - PullRequest
5 голосов
/ 26 февраля 2010

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

Я предполагаю, что либо специальная таблица 'version' в файле SQLite, либо небольшой текстовый файл с номером версии - это путь, но я бы хотел узнать мнение других людей.

Ответы [ 3 ]

4 голосов
/ 01 марта 2010

Нет необходимости в специализированном столе. У SQLite есть для этого прагма, которая называется user_version. SQLite не использует это значение ни для чего, оно полностью оставлено приложению.

Чтобы прочитать версию:

#pragma user_version;

Чтобы установить версию:

#pragma user_version=1;
0 голосов
/ 04 декабря 2012

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

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

0 голосов
/ 26 февраля 2010

Я делаю это, просматривая метки файлов. Если дата модификации файла БД SQLite в пакете .app более поздняя, ​​чем в локальном каталоге документов, я копирую дату из пакета .app поверх ... Вот код, который я использую.

sqlite3 *dbh;           // Underlying database handle
NSString *name;         // Database name (this is the basename part, without the extension)
NSString *pathBundle;   // Path to SQLite DB in the .app folder
NSString *pathLocal;    // Path to SQLite DB in the documents folder on the device

- (BOOL)automaticallyCopyDatabase {                             // Automatically copy DB from .app bundle to device document folder if needed
    ES_CHECK(!dbh, NO, @"Can't autoCopy an already open DB")
    ES_CHECK(name!=nil, NO, @"No DB name specified")
    ES_CHECK(pathBundle!=nil, NO, @"No .app bundle path found, this is a cache DB")
    ES_CHECK(pathLocal!=nil, NO, @"No local document path found, this is a read-only DB")
    NSFileManager *fileManager = [NSFileManager defaultManager];
    NSDictionary *localAttr = [fileManager fileAttributesAtPath:pathLocal traverseLink:YES];
    BOOL needsCopy = NO;
    if (localAttr == nil) {
        needsCopy = YES;
    } else {
        NSDate *localDate;
        NSDate *appDBDate;
        if (localDate = [localAttr objectForKey:NSFileModificationDate]) {
            ES_CHECK([fileManager fileExistsAtPath:pathBundle], NO, @"Internal error: file '%@' does not exist in .app bundle", pathBundle)
            NSDictionary *appDBAttr = [fileManager fileAttributesAtPath:pathBundle traverseLink:YES];
            ES_CHECK(appDBAttr!=nil, NO, @"Internal error: can't get attributes for '%@'", pathBundle)
            appDBDate = [appDBAttr objectForKey:NSFileModificationDate];
            ES_CHECK(appDBDate!=nil, NO, @"Internal error: can't get last modification date for '%@'", pathBundle)
            needsCopy = [appDBDate compare:localDate] == NSOrderedDescending;
        } else {
            needsCopy = YES;
        }
    }
    if (needsCopy) {
        NSError *error;
        BOOL success;
        if (localAttr != nil) {
            success = [fileManager removeItemAtPath:pathLocal error:&error];
            ES_CHECK(success, NO, @"Can't delete file '%@'" ,pathLocal)
        }
        success = [fileManager copyItemAtPath:pathBundle toPath:pathLocal error:&error];
        ES_CHECK(success, NO, @"Can't copy database '%@' to '%@': %@", pathBundle, pathLocal, [error localizedDescription])
        ES_TRACE(@"Copied DB '%@' to '%@'", pathBundle, pathLocal)
        return success;
    }
    return YES;
}

ES_CHECK - это просто макросы, которые расширяются до нуля в режиме выпуска и вызывают исключение в режиме отладки ... Они выглядят так:

#if ES_DEBUG
#define ES_ASSERT(cond) assert(cond);
#define ES_LOG(msg...) NSLog(msg);
#define ES_TRACE(msg...) NSLog(msg);
#else
#define ES_ASSERT(cond)
#define ES_LOG(msg...)
#define ES_TRACE(msg...)
#endif
#define ES_CHECK(cond, ret, msg...) if (!(cond)) { ES_LOG(msg) ES_ASSERT(cond) return (ret); }      // Check with specified return value (when condition fails)
...