归档 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,代码如下所示:
- @interface TRPerson : NSObject <NSCoding>
- @property (nonatomic, copy) NSString * name;
- @property (nonatomic) NSInteger age;
- @end
其次TRPerson遵守NSCoding协议,实现协议方法initWithCoder:和encodeWithCoder:,initWithCoder:方法主要实现解码,encodeWithCoder:方法主要实现编码,代码如下所示:
- - (id)initWithCoder:(NSCoder *)aDecoder
- {
- self = [super init];
- if (self) {
- //解码
- self.name = [aDecoder decodeObjectForKey:@"name"];
- self.age = [aDecoder decodeIntegerForKey:@"age"];
- }
- return self;
- }
- - (void)encodeWithCoder:(NSCoder *)aCoder
- {
- //编码
- [aCoder encodeObject:self.name forKey:@"name"];
- [aCoder encodeInteger:self.age forKey:@"age"];
- }
然后重写description方法,方便TRPerson信息的输出,代码如下所示:
- -(NSString *)description {
- return [NSString stringWithFormat:@"name:%@,age:%d",self.name,self.age];
- }
最后在main函数中创建三个TRPerson对象,并且放入persons数组中保存,persons数组就是需要进行归档的对象,代码如下所示:
- int main(int argc, const char * argv[]) {
- @autoreleasepool {
- TRPerson *person1 = [[TRPerson alloc]init];
- person1.name = @"zhangsan";
- person1.age = 20;
- TRPerson *person2 = [[TRPerson alloc]init];
- person2.name = @"lisi";
- person2.age = 18;
- TRPerson *person3 = [[TRPerson alloc]init];
- person3.name = @"wangwu";
- person3.age = 22;
- NSArray *persons = @[person1,person2,person3];
- }
- return 0;
- }
步骤二:数据归档
首先需要创建一个NSMutableData对象mdata,用于存放归档之后的数据。然后创建NSKeyedArchiver对象archiver,使用initForWritingWithMutableData:方法进行初始化,data参数传递的就是刚才创建的mdata对象,代码如下所示:
- //创建可变的data对象,需要写入数据
- NSMutableData *mdata = [NSMutableData data];
- //创建归档对象archiver
- NSKeyedArchiver *archiver = [[NSKeyedArchiver alloc]initForWritingWithMutableData:mdata];
然后使用encodeObject:forKey:方法进行编码,编码需要指定一个key,反归档时也需要用的这个key,两个可以要保持一致,这里将key设置为“person”,代码如下所示:
- //编码
- [archiver encodeObject:persons forKey:@"person"];
完成编码之后使用finishEncoding结束归档,代码如下所示:
- //结束编码
- [archiver finishEncoding];
最后使用writeToFile:atomically:方法将mdata写入到本地文件保存,代码如下所示:
- [mdata writeToFile:@"/Users/Tarena/Desktop/person" atomically:YES];
运行程序桌面上增加一个名为person的文件,存储的数据就是刚才归档的persons数组,如图-1所示:
图-1
步骤二:数据反归档
首先使用dataWithContentsOfFile:获取一个data对象,然后创建NSKeyedUnarchiver对象unarchiver,使用initForReadingWithData:进行初始化,data参数就是刚才获取的data对象,代码如下所示:
- //获取文件数据
- NSData *data = [NSData dataWithContentsOfFile:@"/Users/Tarena/Desktop/person"];
- //创建反归档对象unarchiver
- NSKeyedUnarchiver *unarchiver = [[NSKeyedUnarchiver alloc]initForReadingWithData:data];
然后使用decodeObjectForKey:方法进行解码获取到一个数组对象persons2,解码时的key要与编码时使用的key保持一致,所以这里的key参数传递“person”,完成解码之后使用finishDecoding结束反归档,代码如下所示:
- //解码
- NSArray *persons2 = [unarchiver decodeObjectForKey:@"person"];
- //结束解码
- [unarchiver finishDecoding];
- NSLog(@"%@",persons2);
最后运行程序将persons2数组输出,在控制台查看结果和persons保存的数据一样,如图-2所示:
图-2
1.4 完整代码
本案例中,main.m文件中的完整代码如下所示:
- #import <Foundation/Foundation.h>
- #import "TRPerson.h"
- int main(int argc, const char * argv[]) {
- @autoreleasepool {
- TRPerson *person1 = [[TRPerson alloc]init];
- person1.name = @"zhangsan";
- person1.age = 20;
- TRPerson *person2 = [[TRPerson alloc]init];
- person2.name = @"lisi";
- person2.age = 18;
- TRPerson *person3 = [[TRPerson alloc]init];
- person3.name = @"wangwu";
- person3.age = 22;
- NSArray *persons = @[person1,person2,person3];
- //创建可变的data对象,需要写入数据
- NSMutableData *mdata = [NSMutableData data];
- //创建归档对象archiver
- NSKeyedArchiver *archiver = [[NSKeyedArchiver alloc]initForWritingWithMutableData:mdata];
- //编码
- [archiver encodeObject:persons forKey:@"person"];
- //结束编码
- [archiver finishEncoding];
- [mdata writeToFile:@"/Users/Tarena/Desktop/person" atomically:YES];
- //获取文件数据
- NSData *data = [NSData dataWithContentsOfFile:@"/Users/Tarena/Desktop/person"];
- //创建反归档对象unarchiver
- NSKeyedUnarchiver *unarchiver = [[NSKeyedUnarchiver alloc]initForReadingWithData:data];
- //解码
- NSArray *persons2 = [unarchiver decodeObjectForKey:@"person"];
- //结束解码
- [unarchiver finishDecoding];
- NSLog(@"%@",persons2);
- }
- return 0;
- }
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,代码如下所示:
- @interface Book : NSObject
- @property (nonatomic, retain) NSString *name;
- @property (nonatomic, retain) NSString *author;
- @property (nonatomic, assign) int page;
- @property (nonatomic, assign) int price;
- @end
为了方便输出Book信息,在Book类中重写description方法,代码如下所示:
- -(NSString *)description {
- return [NSString stringWithFormat:@"name:%@,author:%@,price:%d,page:%d",self.name,self.author,self.price,self.page];
- }
步骤二:MyParser类
首先创建一个MyParser类继承至NSObject,该类需要遵守NSXMLParserDelegate协议,主要通过实现协议方法完成XML文件的解析,代码如下所示:
- @interface MyParser : NSObject<NSXMLParserDelegate>
- @property (nonatomic, retain)NSMutableArray *books;
- @property (nonatomic, retain)Book *currentBook;
- @property (nonatomic, retain)NSString *currentString;
- -(NSMutableArray*)getBooksByData:(NSData *)data;
- @end
其次实现getBooksByData:方法,该方法的功能主要是创建NSXMLParser对象parser,进行XML文件解析获取到全部的Book对象,该方法中需要将parser的委托对象delegate指定为self,代码如下所示:
- -(NSMutableArray *)getBooksByData:(NSData *)data{
- self.books = [NSMutableArray array];
- NSXMLParser *parser = [[NSXMLParser alloc]initWithData:data];
- parser.delegate = self;
- //XML解析
- [parser parse];
- return self.books;
- }
然后在MyParser类中分别实现相关的协议方法,完成XML文件的解析,首先需要实现parser:didStartElement:namespaceURI:qualifiedName:attributes:方法,该方法在遇到开始标签时被调用,因此需要在该方法中创建一个Book对象,用于保存当前正在解析的的图书信息,代码如下所示:
- //遇到一个开始标签时触发
- - (void)parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName attributes:(NSDictionary *)attributeDict{
- if ([elementName isEqualToString:@"book"]) {
- self.currentBook = [[Book alloc]init];
- }
- }
其次实现parser:foundCharacters:方法,该方法在遇到字符串时被调用,因此需要在该方法中保存当前获取到的信息,该信息即是图书的某个属性内容,代码如下所示:
- //遇到字符串时触发
- -(void)parser:(NSXMLParser *)parser foundCharacters:(NSString *)string{
- //获取当前信息
- self.currentString = string;
- }
再实现parser:didEndElement:namespaceURI:qualifiedName:方法,该方法在遇到结束标签时被调用,因此该方法中需要根据结束标签的内容确定self.currentString记录的信息是当前图书的具体哪一个属性的内容,代码如下所示:
- //遇到结束标签时触发
- -(void)parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName{
- //根据结束标签将self.currentString赋值给相应的图书信息
- if ([elementName isEqualToString:@"name"]) {
- self.currentBook.name = self.currentString;
- }else if ([elementName isEqualToString:@"author"]) {
- self.currentBook.author = self.currentString;
- }else if ([elementName isEqualToString:@"price"]) {
- self.currentBook.price = [self.currentString intValue];
- }else if ([elementName isEqualToString:@"page"]) {
- self.currentBook.page = [self.currentString intValue];
- }else if ([elementName isEqualToString:@"book"]){
- [self.books addObject:_currentBook];
- }
- }
实现以上方法就完成了XML文件的解析,最后在main函数中直接通过MyParser的getBooksByData:方法获取到所有的图书对象,代码如下所示:
- int main(int argc, const char * argv[]) {
- @autoreleasepool {
- MyParser *parser = [[MyParser alloc]init];
- NSMutableArray *books = [parser getBooksByData:[NSData dataWithContentsOfFile:@"/Users/Tarena/Desktop/books.xml"]];
- for (Book *book in books) {
- NSLog(@"%@",book);
- }
- }
- return 0;
- }
运行程序,在控制台输出所有图书的信息,如图-4所示:
图-4
2.4 完整代码
本案例中,main.m文件中的完整代码如下所示:
- #import <Foundation/Foundation.h>
- #import "MyParser.h"
- #import "Book.h"
- int main(int argc, const char * argv[]) {
- @autoreleasepool {
- MyParser *parser = [[MyParser alloc]init];
- NSMutableArray *books = [parser getBooksByData:[NSData dataWithContentsOfFile:@"/Users/Tarena/Desktop/books.xml"]];
- for (Book *book in books) {
- NSLog(@"%@",book);
- }
- }
- return 0;
- }
本案例中,MyParser.h文件中的完整代码如下所示:
- #import <Foundation/Foundation.h>
- #import "Book.h"
- @interface MyParser : NSObject<NSXMLParserDelegate>
- @property (nonatomic, retain)NSMutableArray *books;
- @property (nonatomic, retain)Book *currentBook;
- @property (nonatomic, retain)NSString *currentString;
- -(NSMutableArray*)getBooksByData:(NSData *)data;
- @end
本案例中,MyParser.m文件中的完整代码如下所示:
- #import "MyParser.h"
- #import "Book.h"
- @implementation MyParser
- -(NSMutableArray *)getBooksByData:(NSData *)data{
- self.books = [NSMutableArray array];
- NSXMLParser *parser = [[NSXMLParser alloc]initWithData:data];
- parser.delegate = self;
- //XML解析
- [parser parse];
- return self.books;
- }
- //遇到一个开始标签时触发
- - (void)parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName attributes:(NSDictionary *)attributeDict{
- if ([elementName isEqualToString:@"book"]) {
- self.currentBook = [[Book alloc]init];
- }
- }
- //遇到字符串时触发
- -(void)parser:(NSXMLParser *)parser foundCharacters:(NSString *)string{
- //获取当前信息
- self.currentString = string;
- }
- //遇到结束标签时触发
- -(void)parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName{
- //根据结束标签将self.currentString赋值给相应的图书信息
- if ([elementName isEqualToString:@"name"]) {
- self.currentBook.name = self.currentString;
- }else if ([elementName isEqualToString:@"author"]) {
- self.currentBook.author = self.currentString;
- }else if ([elementName isEqualToString:@"price"]) {
- self.currentBook.price = [self.currentString intValue];
- }else if ([elementName isEqualToString:@"page"]) {
- self.currentBook.page = [self.currentString intValue];
- }else if ([elementName isEqualToString:@"book"]){
- [self.books addObject:_currentBook];
- }
- }
- @end
本案例中,Book.h文件中的完整代码如下所示:
- #import <Foundation/Foundation.h>
- @interface Book : NSObject
- @property (nonatomic, retain) NSString *name;
- @property (nonatomic, retain) NSString *author;
- @property (nonatomic, assign) int page;
- @property (nonatomic, assign) int price;
- @end
本案例中,Book.m文件中的完整代码如下所示:
- @implementation Book
- -(NSString *)description {
- return [NSString stringWithFormat:@"name:%@,author:%@,price:%d,page:%d",self.name,self.author,self.price,self.page];
- }
- @end
归档 Archive、解档Unchive、 XML(一)的更多相关文章
- OC对象的归档及解档浅析
一般用在用户登录,保存这个用户的信息 对象归档,就是把内存中对象持久化. 对象解档,就是把持久化的对象读取到内存. oc中对象归档解档大致分为以下几种方法: 从数量上可以分为: 对单个对象归档解档 对 ...
- iOS开发——UI进阶篇(十一)应用沙盒,归档,解档,偏好设置,plist存储,NSData,自定义对象归档解档
1.iOS应用数据存储的常用方式XML属性列表(plist)归档Preference(偏好设置)NSKeyedArchiver归档(NSCoding)SQLite3 Core Data 2.应用沙盒每 ...
- 【KakaJSON手册】07_Coding_归档_解档
KakaJSON可以只用一行代码将常用数据进行归档\解档 后面代码中会用到 file 文件路径 // 文件路径(String或者URL都可以) let file = "/Users/mj/D ...
- iOS开发中的4种数据持久化方式【一、属性列表与归档解档】
iOS中的永久存储,也就是在关机重新启动设备,或者关闭应用时,不会丢失数据.在实际开发应用时,往往需要持久存储数据的,这样用户才能在对应用进行操作后,再次启动能看到自己更改的结果与痕迹.ios开发中, ...
- 数据存储之归档解档 NSKeyedArchiver NSKeyedUnarchiver
在构建应用程序时,有一个重要的问题是如何在每次启动之间持久化数据,以便重现最后一次关闭应用前的状态.在iOS和OS X上,苹果提供了三种选择:Core Data.属性列表(Property List) ...
- iOS 自定义的对象类型的解档和归档
自定义的对象的解档和归档 如果想对自己自定义的类进行解档和归档的话 必须遵循一个协议:NSCoding Student.h 文件 #import <Foundation/Foundation.h ...
- iOS 浅复制、深复制、完全复制的知识点梳理验证(附加归档解档)
在之前转载的一片文章中,文中对浅复制和深复制进行了详细的解读,同时还提到了深复制(one-level-deep copy).完全复制(true copy)的概念,并指出iOS开发中的深复制是单层深赋值 ...
- iOS 浅赋值、深复制、全然复制的知识点梳理验证(附加归档解档)
写于前: 在之前转载的一片文章中.文中对浅复制和深复制进行了具体的解读,同一时候还提到了深复制(one-level-deep copy).全然复制(true copy)的概念,并指出iOS开发中的深复 ...
- IOS数据存储之归档/解档
前言: 前天学习了NSUserDefaults,我们知道NSUserDefaults不能保存自定义对象,所以我们今天来认识一下归档(NSKeyedArchiver)和解档(NSKeyedUnarchi ...
随机推荐
- 生成json对象
JSONObject 对于放入的object,最终生成的json是什么样的? 两个JavaBean: public class ClassBean { private int grade; priva ...
- 工程技巧Linux上建立工程项目
程序中用到的核心代码用库的形式进行封装,并且给出示例程序,下面给出一个程序文件夹的建立脚本. 如运行sh MakeProject.sh PersonNameIdentification PNILib ...
- input[type=text]点击之后无边框, 一进页面就显示光标
1.input[type=text]点击之后无边框 :outline:none; 2. 一进页面就显示光标: <script Language="javascript"> ...
- 设置正确的post数据格式
之前一直使用苏飞的HttpHelper类来访问网络,用起来一直感觉很爽.使用其工具直接生成访问代码很是方便.直到昨天下午做到需要使用wpf来post两个字段数据到服务器,服务器使用ASP.NET MV ...
- API 菜单函数
AppendMenu 在指定的菜单里添加一个菜单项 CheckMenuItem 复选或撤消复选指定的菜单条目 CheckMenuRadioItem 指定一个菜单条目被复选成"单选" ...
- CI 目录下放置index.html,防止直接访问
CI 目录下放置index.html,防止直接访问
- Fence9
题目大意: 求点(0,0),(n,m),(p,0)三点构成的三角形内部(不包括边界)整点的个数. 解题过程:1.直接枚举纵坐标,然后算出两条直线上纵坐标为y的点的横坐标,然后他们中间的点就是符合要求的 ...
- 一模 (4) day1
第一题: 题目大意:给出N个人之间转账的手续X%,求出A转给B至少要多少钱才能使B得到100元.结果保留8位小数:N<=2000 解题过程: 1.很容易看出这题的图论模型,每条边的权值就是(1- ...
- Drag+Drop和MouseClick
项目中的一个树形结节,既要响应拖拽事件.又要响应点击事件.实现的时候没多想,依次实现了tree_MouseClick.tree_MouseDown.tree_MouseMove事件.出现的Bug是,偶 ...
- Linux面试基础题-2
继续我们这面试系列,在这篇文章里我们给出了10个问题.这些问题或者是在以后的文章中出现的问题不一定在面试中会被问到.然而通过这些文章我们呈现出的是一个交互的学习平台,这必将会对你有很大的帮助. 自本系 ...