2010-02-26 2 views
5

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

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

ответ

0

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

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

0

Способ, которым я это делаю, смотря на филе. Если дата изменения файла SQLite DB в пакете .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) 
+0

Этот макрос 'ES_CHECK' интересен ... В режиме отладки вы терпите неудачу с утверждением, но в режиме освобождения вы возвращаете код ошибки, поэтому фактический код ведет себя в разных режимах отладки и выпуска. Таким образом, вы можете только проверить, что вызывающий код может обрабатывать возвращенный код ошибки, поворачивая всю отладку? –

+0

Да. Но ни одна из проверок не проходит, это идея. Если они никогда не справляются с производством, они сокращают рутинную работу, возвращая разумную ценность вместо сбоя ... –

4

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

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

#pragma user_version; 

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

#pragma user_version=1; 
+0

Как программно установить user_version в sqlite? Я могу читать user_version из db, но по какой-то причине обновление терпит неудачу ... !! любая помощь ? – Unicorn

+0

Это то, что происходит, когда я работаю из памяти. :) Ответ исправлен. –

Смежные вопросы