iOS 持久化: Objective-C 和 Xamarin.iOS-Monotouch 的 NSCoding

介绍

应用存储数据。由于无可非议,因为它涉及一份声明。如何在不同的平台上存储数据保持长的效果涉及和经常无聊的谈话,如果在回来的路上数落我和我的同事嘻嘻哈哈,无所事事。

然而iOS库能使数据保存的非常简单,所以,它很好。如果你使用objective-c,数据对象能实现NScoding协议和允许本机库保存并加载数据对象。Montouch稍微需要一个不同的路径,但大多数步骤是相当类似的。两者之间应该是简单直接的。一旦实现这些方法,我们可以使用NSKeyedArchiver和NSKeyedUnarchiver对象保存和加载我们的数据。

Object-C和NSCoding协议

NSCoding是一个简单到只有两个方法就允许保存和加载数据的协议。

NSCoding有两个主要的部分

1 //进程保存对象状态时所调用的方法
2 -(void)encodeWithCoder:(NSCoder *)aCoder
3 //在对象持久化过程中初始化调用
4 -(id)initWithCoder:(NSCoder *)aDecoder
下面我给出一个实现了这个协议的数据类的例子。我们创建一个Book类,继承NSObject,并用NSCoding协议。
01 @interface Book : NSObject < NSCoding > 
02  @property int pageCount;
03  @property NSString* title;
04 @property Publisher* publisher;
05 @end 
06 //我们用下面的方式实现这个类
07 @implementation Book 
08  -(void)encodeWithCoder:(NSCoder *)aCoder { 
09 [aCoder encodeObject:self.title forKey:@"title"]; 
10 [aCoder encodeInt:self.pageCount forKey:@"pageCount"]; 
11 [aCoder encodeObject:self.publisher forKey:@"publisher"]; 
12 }
13  -(id)initWithCoder:(NSCoder *)aDecoder { 
14 self = [super init]; 
15 self.title = (NSString*)[aDecoder decodeObjectForKey:@"title"]; 
16 self.pageCount = [aDecoder decodeIntForKey:@"pageCount"]; 
17 self.publisher = (Publisher*)[aDecoder decodeObjectForKey:@"publisher"]; 
18 returnself; 
19 }
20 @end

这个类有3个属性,前两个是默认类型,最后一个是自定义数据类型将来要用。encodeWithCoder方法将接受一个对象参数来给属性赋值。传递一个字串键值用于将来检索。在这种情况下,我用属性名来作为键名,但这只是我个人的做法而已。因为我们可以控制“encode”方法,所以我们可以选择哪个属性可以保存以及怎样保存。同时,我们也可以在解码是保存额外的信息。比如,如果我们对一个版本数字进行编码

1 [aCoder encodeInt:1 forKey:@"version"];
如果这个版本有变,我们可以在解码器中处理那个版本数字,但这个问题我们日后再谈吧。

那么在对数据进行编码后我们就可以进行持久化处理了。在保存时,iOS进程作为特殊的初始化器来重新创建对象。这个初始化动作就是initWithCoder。从上面的代码我们可以看出保存对象是很简单的,同时也很容易恢复。如果有必要,我们调用“decode”来释放NSCoder对象,然后我们的对象可以从存储里恢复。

用NSKeyedArcheiver和NSKeyedUnachiver可以让持久化神奇、完美和自动的发生。

01 NSData* _savedData;
02  
03 // to save data
04  
05 // the makeData method returns a NSMutableArray of book objects
06 _savedData = [NSKeyedArchiver archivedDataWithRootObject:[self makeData]];
07  
08  
09 // to load data
10  
11 // Since we saved a NSMutableArray when we rehydrate we will get a populated array back
12 NSMutableArray* bookData = (NSMutableArray*) [NSKeyedUnarchiver unarchiveObjectWithData:_savedData];
之前说过我们可以在自定义对象里恢复持久化的数据。我们用支持NSCoding协议的对象比直接从父类调用encodObject要好。事实上,从上面的示例代码中可以看出来。

Monotouch和NSCoder

Monotouch在处理持久化时看起来是如此的熟悉,但不同的是它还需要更多的解释。我们没有直接用NSCoding协议。Monotouch而是提供了一个已被修改过并带有EncodeTo虚方法的NSObject,它同时也有一个额外的构造器可以很容易就能初始化。

那么就让我们来看看Book类在Monotouch中有什么不同

view source
print ?
01 public classBook : NSObject
02 {
03   public int PageCount {get;set;}
04  
05 public string Title {get;set;}
06 public Publisher Publisher {get;set;}
07  
08 public Book ()
09   {
10   }
11   [Export("initWithCoder:")]
12   public Book(NSCoder coder)
13   {
14     this.PageCount = coder.DecodeInt (@"pageCount");
15     NSString str =  (NSString)coder.DecodeObject (@"title");
16    if (str != null) {
17         this.Title = str.ToString (); 
18    
19   this.Publisher = (Publisher) coder.DecodeObject ("publisher"); 
20 }
21 public override void EncodeTo (NSCoder coder)
22 {
23   if (this.Title != null)
24     coder.Encode (new NSString (this.Title), "title");
25     coder.Encode (this.PageCount, "pageCount");
26     if(this.Publisher!=null)
27     coder.Encode (this.Publisher, "publisher");
28 }}

我们可以看出EncodeTo方法和Objective-C中的Encode方法类似。我不得不改变一些我的想法了。在Monotouch中我们可以用基本字串类型。当我们要保存数据时,我们需要将它们打包为NSString,这样在运行时刻就可以很容易的将数据持久化。另一个需要改变的我们需要添加额外的错误和空指针检查。但这没什么大不了的,是很容易做到的。

在解码阶段,我们要添加另一个构造器来作为initWithCoder的输出。

再瞧瞧,容易吧,小伙伴们!

你可能感兴趣的:(ios,Objective-C,编码,存储,interface)