在iOS中存储任意键/值

时间:2013-12-05 17:52:46

标签: ios database sqlite core-data

有没有办法在iOS中存储任意键/值,我知道我可以在SQLite中创建存储JSON键值的列但我想要更高效的东西,所以我只能得到我需要的值查询记录。

最好如果我可以在没有外部数据库(如LevelDB)的情况下执行此操作,但如果您认为这可能是唯一的方法,请告诉我您更喜欢哪一个。

更新

数据将包含从服务器检索的文章(长html文章,标题和日期以及其他未定义数据)和其他元数据,每次用户打开应用程序时都会检索并显示该数据。 (这就是为什么NSUserDefaults不适用于这个用例)

7 个答案:

答案 0 :(得分:8)

我写了一个处理50MB文本的应用程序(大约10,000篇HTML文章)。它们被articleID编入索引。我在这个应用程序中使用过LevelDB,原始Sqlite,带有FMDB的Sqlite,CoreData和NSUserDefaults。

这是我所学到的:

LevelDB为您提供任意键/值访问模式,如果您按顺序读取它们,则读取速度非常快。但是如果你需要随机读取一个键(不使用它的迭代器),它比Sqlite慢得多。

如果您正确使用原始Sqlite,则可以快速进行随机阅读。 (使用索引,覆盖索引等) 但是你将失去读写任意键/值的能力。

FMDB为您提供了一个很好的Objective-C API,但在Objective C和C之间转换数据时浪费了50%的CPU时间(NSString&lt; - &gt; char *)(它仍然比Core Data快4倍+)< / p>

我个人认为核心数据很糟糕。所以我不建议任何人使用它。对不起,我不想回忆起使用CoreData时的那些痛苦。

NSUserDefaults最适合用户设置,仅适用于用户设置,绝对不是长篇文章的解决方案。

我使用原始Sqlite和Google协议缓冲区。

协议缓冲区的编码和解码速度非常快。它还使您能够通过修改.proto文件来添加新字段,无需更改DB方案。你可以在一个proto中存储几个相关的密钥,假设articleMetaData.proto包含titleauthorpublishDate,如果以后需要添加modifyDate你只需将它添加到proto文件中,然后将二进制文件存储在同一列的Sqlite中。

答案 1 :(得分:4)

一个简单的SQLite架构,例如ID(索引)|关键| value应该为您提供所需的自由,具有您需要的速度和查询功能。您可以使用像FMDB这样的瘦包装器,使其比C SQLite API更容易处理。

答案 2 :(得分:2)

就个人而言,我会考虑使用NSCoding协议和NSKeyedArchiver,而不是使用适用于简单数据的NSUserDefaults。让你的对象实现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,因为它可以让您查询数据。

答案 3 :(得分:2)

核心数据听起来像你需要的,不知道你计划存储多少条记录,如果它只是一条然后可能不是核心数据,但如果它很多,那么我认为核心数据将是理想的。

您可能需要通过存储任意键/值来解释您的意思,根据您的问题,它听起来更像结构化数据(标题,日期,文本和其他元数据字段),在这种情况下,核心数据将是完美的。

答案 4 :(得分:1)

看看NSUserDefaults。

NSUserDefaults *userDefaults = [NSUserDefaults standardUserDefaults];

答案 5 :(得分:1)

你有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"];

答案 6 :(得分:0)

如果您只想使用sqlite

YapDatabase可以是另一种选择

它提供这样的API,这似乎是您的用例的理想选择。

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