归档 Archive、解档Unchive、 XML(一)

 

1 使用归档的方式保存文件

1.1 问题

归档是任何对象都可以实现的更常规的方式,可以进行归档的对象需要实现NSCoding协议,而且每个实例变量应该是基本数据类型或者是实现NSCoding协议的某个类的实例。本案例使用归档NSKeyedArchiver和反归档NSKeyedUnarchiver将TRPerson对象写入和读取文件。

1.2 方案

首先创建一个TRPerson类,继承至NSObject,该类有两个属性NSString类型的name和NSInteger类型的age。

其次TRPerson遵守NSCoding协议,实现协议方法initWithCoder:和encodeWithCoder:,initWithCoder:方法主要实现解码,encodeWithCoder:方法主要实现编码。

然后在main函数中创建三个TRPerson对象,并且放入persons数组中保存,persons数组就是需要进行归档的对象。

首先实现数据归档,先需要创建一个NSMutableData对象mdata,用于存放归档之后的数据。然后创建NSKeyedArchiver对象archiver,使用initForWritingWithMutableData:方法进行初始化,data参数传递的就是刚才创建的mdata对象。

再使用encodeObject:forKey:方法进行编码,编码需要指定一个key,反归档时也需要用的这个key,两个可以要保持一致,这里将key设置为“person”。最后使用finishEncoding结束编码。

使用writeToFile:atomically:方法将mdata写入到本地文件保存。

然后实现数据的反归档,先使用dataWithContentsOfFile:获取一个data对象,然后创建NSKeyedUnarchiver对象unarchiver,使用initForReadingWithData:进行初始化,data参数就是刚才获取的data对象。

再使用decodeObjectForKey:方法进行解码获取到一个数组对象persons2,解码时的key要与编码时使用的key保持一致,所以这里的key参数传递“person”。最后使用finishDecoding结束解码。

最后将persons2数组输出,在控制台查看结果。

1.3 步骤

实现此案例需要按照如下步骤进行。

步骤一:创建TRPerson类

首先创建一个TRPerson类,继承至NSObject,该类有两个属性NSString类型的name和NSInteger类型的age,代码如下所示:

 
  1. @interface TRPerson : NSObject <NSCoding>
  2. @property (nonatomic, copy) NSString * name;
  3. @property (nonatomicNSInteger age;
  4. @end

其次TRPerson遵守NSCoding协议,实现协议方法initWithCoder:和encodeWithCoder:,initWithCoder:方法主要实现解码,encodeWithCoder:方法主要实现编码,代码如下所示:

 
  1. (id)initWithCoder:(NSCoder *)aDecoder
  2. {
  3. self [super init];
  4. if (self{
  5. //解码
  6. self.name [aDecoder decodeObjectForKey:@"name"];
  7. self.age [aDecoder decodeIntegerForKey:@"age"];
  8. }
  9. return self;
  10. }
  11. (void)encodeWithCoder:(NSCoder *)aCoder
  12. {
  13. //编码
  14. [aCoder encodeObject:self.name forKey:@"name"];
  15. [aCoder encodeInteger:self.age forKey:@"age"];
  16. }

然后重写description方法,方便TRPerson信息的输出,代码如下所示:

 
  1. -(NSString *)description {
  2. return [NSString stringWithFormat:@"name:%@,age:%d",self.name,self.age];
  3. }

最后在main函数中创建三个TRPerson对象,并且放入persons数组中保存,persons数组就是需要进行归档的对象,代码如下所示:

  1. int main(int argcconst char * argv[]) {
  2. @autoreleasepool {
  3. TRPerson *person1 [[TRPerson alloc]init];
  4. person1.name = @"zhangsan";
  5. person1.age 20;
  6. TRPerson *person2 [[TRPerson alloc]init];
  7. person2.name = @"lisi";
  8. person2.age 18;
  9. TRPerson *person3 [[TRPerson alloc]init];
  10. person3.name = @"wangwu";
  11. person3.age 22;
  12. NSArray *persons = @[person1,person2,person3];
  13. }
  14. return 0;
  15. }

步骤二:数据归档

首先需要创建一个NSMutableData对象mdata,用于存放归档之后的数据。然后创建NSKeyedArchiver对象archiver,使用initForWritingWithMutableData:方法进行初始化,data参数传递的就是刚才创建的mdata对象,代码如下所示:

  1. //创建可变的data对象,需要写入数据
  2. NSMutableData *mdata [NSMutableData data];
  3. //创建归档对象archiver
  4. NSKeyedArchiver *archiver [[NSKeyedArchiver alloc]initForWritingWithMutableData:mdata];

然后使用encodeObject:forKey:方法进行编码,编码需要指定一个key,反归档时也需要用的这个key,两个可以要保持一致,这里将key设置为“person”,代码如下所示:

  1. //编码
  2. [archiver encodeObject:persons forKey:@"person"];

完成编码之后使用finishEncoding结束归档,代码如下所示:

  1. //结束编码
  2. [archiver finishEncoding];

最后使用writeToFile:atomically:方法将mdata写入到本地文件保存,代码如下所示:

  1. [mdata writeToFile:@"/Users/Tarena/Desktop/person" atomically:YES];

运行程序桌面上增加一个名为person的文件,存储的数据就是刚才归档的persons数组,如图-1所示:

图-1

步骤二:数据反归档

首先使用dataWithContentsOfFile:获取一个data对象,然后创建NSKeyedUnarchiver对象unarchiver,使用initForReadingWithData:进行初始化,data参数就是刚才获取的data对象,代码如下所示:

  1. //获取文件数据
  2. NSData *data [NSData dataWithContentsOfFile:@"/Users/Tarena/Desktop/person"];
  3. //创建反归档对象unarchiver
  4. NSKeyedUnarchiver *unarchiver [[NSKeyedUnarchiver alloc]initForReadingWithData:data];

然后使用decodeObjectForKey:方法进行解码获取到一个数组对象persons2,解码时的key要与编码时使用的key保持一致,所以这里的key参数传递“person”,完成解码之后使用finishDecoding结束反归档,代码如下所示:

  1. //解码
  2. NSArray *persons2 [unarchiver decodeObjectForKey:@"person"];
  3. //结束解码
  4. [unarchiver finishDecoding];
  5. NSLog(@"%@",persons2);

最后运行程序将persons2数组输出,在控制台查看结果和persons保存的数据一样,如图-2所示:

图-2

1.4 完整代码

本案例中,main.m文件中的完整代码如下所示:

 
  1. #import <Foundation/Foundation.h>
  2. #import "TRPerson.h"
  3. int main(int argcconst char * argv[]) {
  4. @autoreleasepool {
  5. TRPerson *person1 [[TRPerson alloc]init];
  6. person1.name = @"zhangsan";
  7. person1.age 20;
  8. TRPerson *person2 [[TRPerson alloc]init];
  9. person2.name = @"lisi";
  10. person2.age 18;
  11. TRPerson *person3 [[TRPerson alloc]init];
  12. person3.name = @"wangwu";
  13. person3.age 22;
  14. NSArray *persons = @[person1,person2,person3];
  15. //创建可变的data对象,需要写入数据
  16. NSMutableData *mdata [NSMutableData data];
  17. //创建归档对象archiver
  18. NSKeyedArchiver *archiver [[NSKeyedArchiver alloc]initForWritingWithMutableData:mdata];
  19. //编码
  20. [archiver encodeObject:persons forKey:@"person"];
  21. //结束编码
  22. [archiver finishEncoding];
  23. [mdata writeToFile:@"/Users/Tarena/Desktop/person" atomically:YES];
  24. //获取文件数据
  25. NSData *data [NSData dataWithContentsOfFile:@"/Users/Tarena/Desktop/person"];
  26. //创建反归档对象unarchiver
  27. NSKeyedUnarchiver *unarchiver [[NSKeyedUnarchiver alloc]initForReadingWithData:data];
  28. //解码
  29. NSArray *persons2 [unarchiver decodeObjectForKey:@"person"];
  30. //结束解码
  31. [unarchiver finishDecoding];
  32. NSLog(@"%@",persons2);
  33. }
  34. return 0;
  35. }
 

2 使用NSXML框架解析XML文件

2.1 问题

XML可扩展标记语言,是一种运用于各种计算机语言中的非常重要的数据交换格式,属性列表(plist)就是以XML形式存储的,本案例演示如何使用XML框架解析XML文件。

2.2 方案

首先准备一个XML文件,该XML文件保存的是图书的信息,包括书名、作者、价钱以及页数,如图-3所示:

图-3

其次创建一个Book类用于保存解析出来的图书信息,该类继承至NSObject,有如下属性:

NSString类型的name,用于保存书名;

NSString类型的author,用于保存图书作者;

int类型的page,用于保存图书的页数;

int类型的price,用于保存图书的价钱。

然后创建一个MyParser类继承至NSObject,该类需要遵守NSXMLParserDelegate协议,主要通过实现协议方法完成XML文件的解析。

MyParser类有如下属性和方法:

NSMutableArray类型的books,用于保存解析出来的全部Book对象;

Book类型的currentBook,用于保存当前正在解析的Book对象;

NSString的currentString,用于保存当前正在解析的内容;

-(NSMutableArray*)getBooksByData:(NSData *)data方法的功能主要是创建NSXMLParser对象parser,进行XML文件解析获取到全部的Book对象,该方法中需要将parser的委托对象delegate指定为self。

最后在MyParser类中分别实现相关的协议方法,完成XML文件的解析。在main函数中就可以直接通过MyParser的getBooksByData:方法获取到所有的图书对象。

2.3 步骤

实现此案例需要按照如下步骤进行。

步骤一:创建Book对象

首先创建一个Book类用于保存解析出来的图书信息,该类继承至NSObject,代码如下所示:

 
  1. @interface Book : NSObject
  2. @property (nonatomic, retainNSString *name;
  3. @property (nonatomic, retainNSString *author;
  4. @property (nonatomic, assignint page;
  5. @property (nonatomic, assignint price;
  6. @end

为了方便输出Book信息,在Book类中重写description方法,代码如下所示:

  1. -(NSString *)description {
  2. return [NSString stringWithFormat:@"name:%@,author:%@,price:%d,page:%d",self.name,self.author,self.price,self.page];
  3. }

步骤二:MyParser类

首先创建一个MyParser类继承至NSObject,该类需要遵守NSXMLParserDelegate协议,主要通过实现协议方法完成XML文件的解析,代码如下所示:

 
  1. @interface MyParser : NSObject<NSXMLParserDelegate>
  2. @property (nonatomic, retain)NSMutableArray *books;
  3. @property (nonatomic, retain)Book *currentBook;
  4. @property (nonatomic, retain)NSString *currentString;
  5. -(NSMutableArray*)getBooksByData:(NSData *)data;
  6. @end

其次实现getBooksByData:方法,该方法的功能主要是创建NSXMLParser对象parser,进行XML文件解析获取到全部的Book对象,该方法中需要将parser的委托对象delegate指定为self,代码如下所示:

 
  1. -(NSMutableArray *)getBooksByData:(NSData *)data{
  2. self.books [NSMutableArray array];
  3. NSXMLParser *parser [[NSXMLParser alloc]initWithData:data];
  4. parser.delegate = self;
  5. //XML解析
  6. [parser parse];
  7. return self.books;
  8. }

然后在MyParser类中分别实现相关的协议方法,完成XML文件的解析,首先需要实现parser:didStartElement:namespaceURI:qualifiedName:attributes:方法,该方法在遇到开始标签时被调用,因此需要在该方法中创建一个Book对象,用于保存当前正在解析的的图书信息,代码如下所示:

 
  1. //遇到一个开始标签时触发
  2. (void)parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qNameattributes:(NSDictionary *)attributeDict{
  3. if ([elementName isEqualToString:@"book"]) {
  4. self.currentBook [[Book alloc]init];
  5. }
  6. }

其次实现parser:foundCharacters:方法,该方法在遇到字符串时被调用,因此需要在该方法中保存当前获取到的信息,该信息即是图书的某个属性内容,代码如下所示:

  1. //遇到字符串时触发
  2. -(void)parser:(NSXMLParser *)parser foundCharacters:(NSString *)string{
  3. //获取当前信息
  4. self.currentString = string;
  5. }

再实现parser:didEndElement:namespaceURI:qualifiedName:方法,该方法在遇到结束标签时被调用,因此该方法中需要根据结束标签的内容确定self.currentString记录的信息是当前图书的具体哪一个属性的内容,代码如下所示:

 
  1. //遇到结束标签时触发
  2. -(void)parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName{
  3. //根据结束标签将self.currentString赋值给相应的图书信息
  4. if ([elementName isEqualToString:@"name"]) {
  5. self.currentBook.name = self.currentString;
  6. }else if ([elementName isEqualToString:@"author"]) {
  7. self.currentBook.author = self.currentString;
  8. }else if ([elementName isEqualToString:@"price"]) {
  9. self.currentBook.price [self.currentString intValue];
  10. }else if ([elementName isEqualToString:@"page"]) {
  11. self.currentBook.page [self.currentString intValue];
  12. }else if ([elementName isEqualToString:@"book"]){
  13. [self.books addObject:_currentBook];
  14. }
  15. }

实现以上方法就完成了XML文件的解析,最后在main函数中直接通过MyParser的getBooksByData:方法获取到所有的图书对象,代码如下所示:

 
  1. int main(int argcconst char * argv[]) {
  2. @autoreleasepool {
  3. MyParser *parser [[MyParser alloc]init];
  4. NSMutableArray *books [parser getBooksByData:[NSData dataWithContentsOfFile:@"/Users/Tarena/Desktop/books.xml"]];
  5. for (Book *book in books{
  6. NSLog(@"%@",book);
  7. }
  8. }
  9. return 0;
  10. }

运行程序,在控制台输出所有图书的信息,如图-4所示:

图-4

2.4 完整代码

本案例中,main.m文件中的完整代码如下所示:

 
  1. #import <Foundation/Foundation.h>
  2. #import "MyParser.h"
  3. #import "Book.h"
  4. int main(int argcconst char * argv[]) {
  5. @autoreleasepool {
  6. MyParser *parser [[MyParser alloc]init];
  7. NSMutableArray *books [parser getBooksByData:[NSData dataWithContentsOfFile:@"/Users/Tarena/Desktop/books.xml"]];
  8. for (Book *book in books{
  9. NSLog(@"%@",book);
  10. }
  11. }
  12. return 0;
  13. }
 

本案例中,MyParser.h文件中的完整代码如下所示:

 
  1. #import <Foundation/Foundation.h>
  2. #import "Book.h"
  3. @interface MyParser : NSObject<NSXMLParserDelegate>
  4. @property (nonatomic, retain)NSMutableArray *books;
  5. @property (nonatomic, retain)Book *currentBook;
  6. @property (nonatomic, retain)NSString *currentString;
  7. -(NSMutableArray*)getBooksByData:(NSData *)data;
  8. @end
 

本案例中,MyParser.m文件中的完整代码如下所示:

 
  1. #import "MyParser.h"
  2. #import "Book.h"
  3. @implementation MyParser
  4. -(NSMutableArray *)getBooksByData:(NSData *)data{
  5. self.books [NSMutableArray array];
  6. NSXMLParser *parser [[NSXMLParser alloc]initWithData:data];
  7. parser.delegate = self;
  8. //XML解析
  9. [parser parse];
  10. return self.books;
  11. }
  12. //遇到一个开始标签时触发
  13. (void)parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qNameattributes:(NSDictionary *)attributeDict{
  14. if ([elementName isEqualToString:@"book"]) {
  15. self.currentBook [[Book alloc]init];
  16. }
  17. }
  18. //遇到字符串时触发
  19. -(void)parser:(NSXMLParser *)parser foundCharacters:(NSString *)string{
  20. //获取当前信息
  21. self.currentString = string;
  22. }
  23. //遇到结束标签时触发
  24. -(void)parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName{
  25. //根据结束标签将self.currentString赋值给相应的图书信息
  26. if ([elementName isEqualToString:@"name"]) {
  27. self.currentBook.name = self.currentString;
  28. }else if ([elementName isEqualToString:@"author"]) {
  29. self.currentBook.author = self.currentString;
  30. }else if ([elementName isEqualToString:@"price"]) {
  31. self.currentBook.price [self.currentString intValue];
  32. }else if ([elementName isEqualToString:@"page"]) {
  33. self.currentBook.page [self.currentString intValue];
  34. }else if ([elementName isEqualToString:@"book"]){
  35. [self.books addObject:_currentBook];
  36. }
  37. }
  38. @end
 

本案例中,Book.h文件中的完整代码如下所示:

 
  1. #import <Foundation/Foundation.h>
  2. @interface Book : NSObject
  3. @property (nonatomic, retainNSString *name;
  4. @property (nonatomic, retainNSString *author;
  5. @property (nonatomic, assignint page;
  6. @property (nonatomic, assignint price;
  7. @end
 

本案例中,Book.m文件中的完整代码如下所示:

 
  1. @implementation Book
  2. -(NSString *)description {
  3. return [NSString stringWithFormat:@"name:%@,author:%@,price:%d,page:%d",self.name,self.author,self.price,self.page];
  4. }
  5. @end
原文地址:https://www.cnblogs.com/hytx/p/5051925.html