【问题标题】:iOS persistent storage strategyiOS 持久化存储策略
【发布时间】:2012-02-02 09:24:59
【问题描述】:

我正在开发一个将数据保存到本地文件系统的应用程序。将要保存的数据主要是 NSString 和 NSDate。数据不会经常保存,在典型使用情况下可能会输入 10 次新数据。数据当然也应该是可检索的(CRUD)

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

我是否应该归档课程模型?使用 SQLLite3?

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

【问题讨论】:

  • 如果数据量不大,如你所说..你可以使用NSUserDefaults...它简单易用。

标签: objective-c cocoa-touch persistence save


【解决方案1】:

我建议你选择NSUserDefaults。这无疑是存储与您的应用程序相关的信息和任何应用程序相关数据的最佳方法。检查documentation!!

【讨论】:

    【解决方案2】:

    这种数据似乎很容易存储和检索,并且没有任何其他依赖项,例如极其复杂的对象图。

    您应该将此数据存储在平面文件或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
    

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

    【讨论】:

    • 感谢您的详尽回答。实际上,我的应用程序将有 2 个具有聚合关系的数据模型。所以我的第一个数据模型(我们称之为 DataA)将有一个 NSString 和 NSDate 也将引用第二个数据模型(我们称之为 DataB),它本身将由一个 NSString 和一个 NSArray 组成。所以现在变得有点复杂了。如果 DataB 中的一个对象被删除,它当然应该不再存在于 DataA 中。
    • @PeterWarbo 如果是这种情况,我建议您使用 Core Data,因为它是执行级联关系规则等的最简单方法。实现起来应该很简单,尽管我对设置 Core Data 堆栈只是为了做到这一点的权衡持怀疑态度......
    • 所以基本上可以归结为使用我的数据模型归档或使用 Core Data?
    • @PeterWarbo 是的。在这种情况下,我完全不推荐sqlite
    • @PeterWarbo 当您绝对需要使用 SQL 过滤数据并且还需要它通过删除 Core Data 中间人提供的性能提升时。到目前为止,我还没有遇到满足这些条件的情况,所以如果可以的话,我会尽量远离它。更不用说sqlite3 API 处理起来非常麻烦。
    【解决方案3】:

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

    即使对象图很小,您也将获得缓存对象管理和免费的撤消/重做管理。

    【讨论】:

      猜你喜欢
      • 2018-07-01
      • 1970-01-01
      • 2011-07-22
      • 2010-12-18
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-07-14
      • 1970-01-01
      相关资源
      最近更新 更多