iOS持久化存储策略

17

我正在开发一款应用程序,将数据保存到本地文件系统。将要保存的数据大部分会是NSString和NSDate类型。这些数据不会经常被保存,典型情况下可能只有10次左右的新数据输入。当然,这些数据也应该可检索(CRUD)。

我应该如何保存这些数据呢?首先,有必要对这些对象进行建模吗?如果不需要,我应该使用属性列表还是SQLLite3?

否则,我应该档案化类模型吗?使用SQLLite3?

编辑:我无意中遗漏了有关应用程序的一些重要信息。实际上,我的应用程序将具有2个具有聚合关系的数据模型。所以,我的第一个数据模型(让我们称其为DataA),它将有一个NSString和一个NSDate,还将引用第二个数据模型(让我们称其为DataB),它本身将包含一个NSString和一个NSArray。现在变得有点复杂了。如果从DataB删除一个对象,则它在DataA中当然也应该消失(但DataA的其余部分应该保持不变)。


如果数据量不是很大,就像你所说的那样,可以使用NSUserDefaults...它简单易用。 - Bonnie
3个回答

18

这种数据似乎非常简单易于存储和检索,并且没有其他依赖关系,例如可怕的复杂对象图。

您应该将此数据存储在一个平面文件或 NSUserDefaults 中。

我将为您提供两个示例,分别使用对象归档和 NSCoding 协议:

@interface ApplicationData <NSCopying, NSCoding> {}

@property (nonatomic, strong) NSDate *someDate;
@property (nonatomic, strong) NSDate *someOtherDate;

@property (nonatomic, copy) NSString *someString;
@property (nonatomic, copy) NSString *someOtherString;

@end

@implementation ApplicationData

@synthesize someDate = _someDate, someOtherDate = _someOtherDate, someString = _someString, someOtherString = _someOtherString;

- (NSArray *)keys {
   static dispatch_once_t once;
   static NSArray *keys = nil;
   dispatch_once(&once, ^{
      keys = [NSArray arrayWithObjects:@"someString", @"someOtherString", @"someDate", @"someOtherDate", nil];
  });
   return keys;
}

- (id) copyWithZone:(NSZone *) zone {
    ApplicationData *data = [[[self class] allocWithZone:zone] init];
    if(data) {
        data.someString = _someString;
        data.someOtherString = _someOtherString;     

        data.someDate = _someDate;
        data.someOtherDate = _someOtherDate;
        //...
    }
    return data;
 }

 - (void) encodeWithCoder:(NSCoder *) coder {
     [super encodeWithCoder:coder];

     NSDictionary *pairs = [self dictionaryWithValuesForKeys:[self keys]];

     for(NSString *key in keys) {
        [coder encodeObject:[pairs objectForKey:key] forKey:key];
     }
  }


  - (id) initWithCoder:(NSCoder *) decoder {
     self = [super initWithCoder:decoder];
     if(self) {
        for(NSString *key in [self keys]) {
           [self setValue:[decoder decodeObjectForKey:key] forKey:key];
        }
     }
     return self;
  }

  @end

然后,在你的应用程序委托中,你可以这样做:

@interface AppDelegate (Persistence)

@property (nonatomic, strong) ApplicationData *data;

- (void)saveApplicationDataToFlatFile;
- (void)loadApplicationDataFromFlatFile;
- (void)saveApplicationDataToUserDefaults;
- (void)loadApplicationDataFromUserDefaults;

@end

@implementation AppDelegate (Persistence) 
@synthesize data;

- (NSString *)_dataFilePath {
   static NSString *path = nil;
   static dispatch_once_t once;
   dispatch_once(&once, ^{
     path = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) stringByAppendingPathComponent:@"xAppData.dat"];
   });
   return path;
}

- (void)loadApplicationDataFromUserDefaults {        
   NSData *archivedData = [[NSUserDefaults standardUserDefaults] objectForKey:@"appData"];
   self.data = [NSKeyedUnarchiver unarchiveObjectWithData:archivedData];
}

- (void)saveApplicationDataToUserDefaults {
   NSData *archivedData = [NSKeyedArchiver archivedDataWithRootObject:self.data];
   [[NSUserDefaults standardUserDefaults] setObject:archivedData forKey:@"appData"];
   [[NSUserDefaults standardUserDefaults] synchronize];
}

- (void)loadApplicationDataFromFlatFile {
   NSData *archivedData = [NSData dataWithContentsOfFile:[self _dataFilePath]];
   self.data = [NSKeyedUnarchiver unarchiveObjectWithData:archivedData];
}

- (void)saveApplicationDataToFlatFile {  
   NSData *archivedData = [NSKeyedArchiver archivedDataWithRootObject:self.data];
   [archivedData writeToFile:[self _dataFilePath] atomically:YES];
}

@end

免责声明:我没有测试过这段代码。


感谢您详尽的回答。实际上,我的应用程序将有两个数据模型,它们具有汇总关系。因此,我的第一个数据模型(让我们称其为DataA),它将具有NSString和NSDate,还将引用第二个数据模型(让我们称其为DataB),它本身将由NSString和NSArray组成。现在变得有点复杂了。如果从DataB中删除了一个对象,则当然应该在DataA中停止存在。 - Peter Warbo
如果是这样的话,我建议您使用Core Data,因为这将是实现级联关系规则等最简单的方法。虽然我对设置Core Data堆栈来完成此操作的权衡持怀疑态度,但它应该非常容易实现。 - Jacob Relkin
所以基本上,这归结为使用我的数据模型的归档或使用Core Data? - Peter Warbo
@PeterWarbo 是的。在这种情况下,我根本不建议直接使用sqlite - Jacob Relkin
谢谢,这很有趣。在什么情况下直接使用SQLite会更好呢? - Peter Warbo
1
@PeterWarbo 当您绝对需要使用SQL过滤数据并且需要通过删除Core Data中间层提供的性能优势时,我还没有遇到过完全满足这些条件的情况,所以如果可以的话,我会尽量避免使用。更不用说“sqlite3”API让人头疼难处理了。 - Jacob Relkin

1
我建议您使用NSUserDefaults。这绝对是存储与您的应用程序和任何应用程序相关数据有关的信息的最佳方法。请查看文档!!

1

如果你只有一组有限的数据,NSUserDefault是一个不错的选择。 但如果你考虑筛选和获取,那么你应该看看Core Data来存储对象。

即使对象图很小,你也会获得缓存对象管理和自由撤消/重做管理。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接