Хранение произвольных ключей/значений в iOS

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

Предпочтительно Если бы я мог сделать это без внешней базы данных (например, LevelDB), но если вы считаете, что это единственный способ, сообщите мне, какой из них вы предпочитаете.

Update:

Данные будут содержать статьи (длинные html-статьи, заголовок и дату и другие данные undefined), полученные с сервера и другие метаданные, они будут извлекаться и отображаться каждый раз, когда пользователь открывает приложение. (поэтому NSUserDefaults не будет работать для этого случая использования)

Ответы

Ответ 1

Я написал приложение, посвященное 50 МБ текстам (около 10 000 статей в формате HTML). Они индексируются с помощью articleID. Я использовал LevelDB, raw Sqlite, Sqlite с FMDB, CoreData и NSUserDefaults в этом приложении.

Вот что я узнал:

LevelDB дает вам произвольный шаблон доступа к ключу/значению, и скорость чтения чрезвычайно быстро, если вы читаете их последовательно. Но если вам нужно читать ключ случайным образом (не используя его итератор), он намного медленнее, чем Sqlite.

Raw Sqlite быстро используется для случайного чтения, если вы используете его правильно. (Используйте индексы, индексы обложки и т.д.) Но вы потеряете способность читать и писать произвольный ключ/значение.

FMDB дает вам хороший API Objective-C, но 50% процессорное время теряется при преобразовании данных между объектами C и C (NSString ↔ char *) (он все еще намного быстрее, чем Core Data, 4X +)

Лично я думаю, что Core Data отстой. Поэтому я не буду рекомендовать его никому для использования. Извините, я не хочу вспоминать эту боль при использовании CoreData.

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

Я использую raw Sqlite и буфер протокола Google.

Протокольный буфер очень быстрый для кодирования и декодирования. Он также дает вам возможность добавлять новые поля, изменяя его .proto файл, не требуется изменение схемы БД. Вы можете сохранить несколько связанных ключей в одном прото, пусть articleMetaData.proto содержит title, author и publishDate, если через некоторое время вам нужно добавить modifyDate, вы просто добавите его в файл proto и сохраните двоичный файл в Sqlite в том же столбце.

Ответ 2

Простая схема SQLite, такая как идентификатор (индексированный) | ключ | ценность должна дать вам свободу, которую вы хотите, со скоростью и запросами, которые вам нужны. Вы можете использовать тонкую оболочку, такую ​​как FMDB, чтобы сделать ее намного проще, чем C SQLite API.

Ответ 3

Лично, вместо использования NSUserDefaults, который подходит для простых данных, я бы рассмотрел использование протокола NSCoding и NSKeyedArchiver. Пусть ваши объекты реализуют протокол NSCoding, а затем используют что-то вроде этого, чтобы архивировать/разблокировать их:

+ (NSObject *)readArchiveFile:(NSString *)inFileName
{
    NSFileManager *fileMgr = [NSFileManager defaultManager];
    NSString *documentsDirectoryPath = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES)[0];
    NSString *filePath = [NSString stringWithFormat:@"%@/%@", documentsDirectoryPath, inFileName];

    NSObject *returnObject = nil;
    if( [fileMgr fileExistsAtPath:filePath] )
    {

        returnObject = [NSKeyedUnarchiver unarchiveObjectWithFile:filePath];
    }

    return returnObject;

}

+ (void)archiveFile:(NSString *)inFileName inObject:(NSObject *)inObject
{
    NSString *documentsDirectoryPath = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES)[0];
    NSString *filePath = [NSString stringWithFormat:@"%@/%@", documentsDirectoryPath, inFileName];
    BOOL didSucceed = [NSKeyedArchiver archiveRootObject:inObject toFile:filePath];
    if( !didSucceed )
    {
        NSLog(@"File %@ write operation %@", inFileName, didSucceed ? @"success" : @"error" );
    }

}

+ (void)deleteFile:(NSString *)inFileName
{
    NSFileManager *fileMgr = [NSFileManager defaultManager];
    NSString *documentsDirectoryPath = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES)[0];
    NSString *filePath = [NSString stringWithFormat:@"%@/%@", documentsDirectoryPath, inFileName];
    NSError *error;
    if ( [fileMgr fileExistsAtPath:filePath] && [fileMgr removeItemAtPath:filePath error:&error] != YES)
    {
        NSLog(@"Unable to delete file: %@", [error localizedDescription]);
    }
}

Кроме того, я бы рассмотрел использование CoreData, поскольку он дает вам возможность запрашивать ваши данные.

Ответ 4

Основные данные звучат так, как вам нужно, но не уверены, сколько записей вы планируете хранить, если это только один, а может быть, не Core Data, но если бы это было так, я бы подумал, что Core Data будет идеальным.

Возможно, вам нужно будет объяснить, что вы имеете в виду, сохраняя произвольные ключи/значения, исходя из вашего вопроса, это скорее похоже на структурированные данные (название, дата, текст и другие поля метаданных), и в этом случае Core Data будет идеальным.

Ответ 5

Посмотрите на NSUserDefaults.

NSUserDefaults *userDefaults = [NSUserDefaults standardUserDefaults];

Ответ 6

У вас есть NSUserDefaults, и там вы можете хранить информацию.

Удерживайте только несколько вещей: 1 - Если вы не оставите приложение, необходимо выполнить синхронизацию для хранения информации; 2 - Вы можете хранить и получать и редактировать информацию всегда

NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
[defaults setObject:self.emailToSend forKey:@"teste.email"];
[defaults synchronize];


NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
[alert textFieldAtIndex:0].text = [defaults objectForKey:@"teste.email"];

Ответ 7

YapDatabase может быть другой опцией, если вы просто хотите использовать sqlite

Он предоставляет API, как это, что кажется идеальным для вашего использования.

- (void)setObject:(nullable id)object
           forKey:(NSString *)key
     inCollection:(nullable NSString *)collection
     withMetadata:(nullable id)metadata;