Я хочу включать обновленную базу данных SQLite с новой версией приложения. Мои копии приложений файл базы данных в каталог Documents на запуске. Что лучший способ состоит в том, чтобы сделать этот вид управления версиями (помимо использования Базовых Данных)?
Я предполагаю, что или специальная таблица 'версии' в файле SQLite или небольшой текстовый файл с номером версии являются способом пойти, но я хотел бы получить другие мнения народов.
Я делаю это, просматривая метки файлов. Если дата изменения файла 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)
Нет необходимости в специализированный стол. В SQLite для этого есть прагма user_version
. SQLite ни для чего не использует это значение, это полностью оставлено на усмотрение приложения.
Чтобы прочитать версию:
#pragma user_version;
Чтобы установить версию:
#pragma user_version=1;