有没有办法在iOS中存储任意键/值,我知道我可以在SQLite中创建存储JSON键值的列但我想要更高效的东西,所以我只能得到我需要的值查询记录。
最好如果我可以在没有外部数据库(如LevelDB)的情况下执行此操作,但如果您认为这可能是唯一的方法,请告诉我您更喜欢哪一个。
更新
数据将包含从服务器检索的文章(长html文章,标题和日期以及其他未定义数据)和其他元数据,每次用户打开应用程序时都会检索并显示该数据。 (这就是为什么NSUserDefaults不适用于这个用例)
答案 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
包含title
,author
和publishDate
,如果以后需要添加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)
YapDatabase可以是另一种选择
它提供这样的API,这似乎是您的用例的理想选择。
- (void)setObject:(nullable id)object
forKey:(NSString *)key
inCollection:(nullable NSString *)collection
withMetadata:(nullable id)metadata;