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 (nonatomic) NSInteger 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 argc, const 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 argc, const 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, retain) NSString *name;
  3. @property (nonatomic, retain) NSString *author;
  4. @property (nonatomic, assign) int page;
  5. @property (nonatomic, assign) int 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 *)qName attributes:(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 argc, const 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 argc, const 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 *)qName attributes:(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, retain) NSString *name;
  4. @property (nonatomic, retain) NSString *author;
  5. @property (nonatomic, assign) int page;
  6. @property (nonatomic, assign) int 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

归档 Archive、解档Unchive、 XML(一)的更多相关文章

  1. OC对象的归档及解档浅析

    一般用在用户登录,保存这个用户的信息 对象归档,就是把内存中对象持久化. 对象解档,就是把持久化的对象读取到内存. oc中对象归档解档大致分为以下几种方法: 从数量上可以分为: 对单个对象归档解档 对 ...

  2. iOS开发——UI进阶篇(十一)应用沙盒,归档,解档,偏好设置,plist存储,NSData,自定义对象归档解档

    1.iOS应用数据存储的常用方式XML属性列表(plist)归档Preference(偏好设置)NSKeyedArchiver归档(NSCoding)SQLite3 Core Data 2.应用沙盒每 ...

  3. 【KakaJSON手册】07_Coding_归档_解档

    KakaJSON可以只用一行代码将常用数据进行归档\解档 后面代码中会用到 file 文件路径 // 文件路径(String或者URL都可以) let file = "/Users/mj/D ...

  4. iOS开发中的4种数据持久化方式【一、属性列表与归档解档】

    iOS中的永久存储,也就是在关机重新启动设备,或者关闭应用时,不会丢失数据.在实际开发应用时,往往需要持久存储数据的,这样用户才能在对应用进行操作后,再次启动能看到自己更改的结果与痕迹.ios开发中, ...

  5. 数据存储之归档解档 NSKeyedArchiver NSKeyedUnarchiver

    在构建应用程序时,有一个重要的问题是如何在每次启动之间持久化数据,以便重现最后一次关闭应用前的状态.在iOS和OS X上,苹果提供了三种选择:Core Data.属性列表(Property List) ...

  6. iOS 自定义的对象类型的解档和归档

    自定义的对象的解档和归档 如果想对自己自定义的类进行解档和归档的话 必须遵循一个协议:NSCoding Student.h 文件 #import <Foundation/Foundation.h ...

  7. iOS 浅复制、深复制、完全复制的知识点梳理验证(附加归档解档)

    在之前转载的一片文章中,文中对浅复制和深复制进行了详细的解读,同时还提到了深复制(one-level-deep copy).完全复制(true copy)的概念,并指出iOS开发中的深复制是单层深赋值 ...

  8. iOS 浅赋值、深复制、全然复制的知识点梳理验证(附加归档解档)

    写于前: 在之前转载的一片文章中.文中对浅复制和深复制进行了具体的解读,同一时候还提到了深复制(one-level-deep copy).全然复制(true copy)的概念,并指出iOS开发中的深复 ...

  9. IOS数据存储之归档/解档

    前言: 前天学习了NSUserDefaults,我们知道NSUserDefaults不能保存自定义对象,所以我们今天来认识一下归档(NSKeyedArchiver)和解档(NSKeyedUnarchi ...

随机推荐

  1. LaTeX测试

    首先输出个\(\LaTeX\ \),看上去非常高端! 然后上论文,测试以后发现不行QAQQQ 貌似只能插入一个公式来着...比如:$\theta(\vec{u},\ \vec{v}) = arccos ...

  2. HTTP 错误 500.22 - Internal Server Error 检测到在集成的托管管道模式下不适用的 ASP.NET 设置

    答案:在将WebDataHelper升级到VS2013是出现的这个错误,这个程序使用了URL重写的技术, 解决方法是:需要将重写的配置,迁移到system.webServer配置节中

  3. JNI的一些知识:

    JNI字段描述符"([Ljava/lang/String;)V" 2012-05-31 12:16:09| 分类: Android |举报|字号 订阅 "([Ljava/ ...

  4. PHP 多线程扩展(正儿八经的线程)pthreads安装

    环境CentOS 6.3 64bit,php 5.4.5 pthreads需要线程安全环境, 下载php的安装包,解压: tar zxvf php-5.4.5.tar.gz//名字是不是这个我不确定, ...

  5. ZOJ 3647 Gao the Grid dp,思路,格中取同一行的三点,经典 难度:3

    http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemId=4837 三角形的总数=格子中任取3个点的组合数-同一横行任取3个点数目-同一纵行 ...

  6. 标准库源码--wsgi服务器

    功能模块化带来可自由组装的便利: 使用python的mixin特性装配 class ThreadHTTPServer(ThreadingMixin, HTTPServer): pass 上面表示1个请 ...

  7. Program C 暴力求解

    Description   A ring is composed of n (even number) circles as shown in diagram. Put natural numbers ...

  8. Android Studio 使用genymotion 模拟器运行app时 提示找不到任何设备

    原因是使用了genymotion 默认的Android toos .打开genymotion  选择设置  ADB  使用自己的SDKtools 选择Android Studio 使用的SDK位置就行 ...

  9. pyqt5 笔记(二)实现http请求发送

    上个图~ index.py 文件 # -*- coding: utf-8 -*- from PyQt5 import QtWidgets,QtCore #从pyqt库导入QtWindget通用窗口类 ...

  10. PHP time() 函数

    定义和用法 time() 函数返回当前时间的 Unix 时间戳. 语法 time(void) 参数 描述 void 可选. 说明 返回自从 Unix 纪元(格林威治时间 1970 年 1 月 1 日 ...