将一个或多个OC对象写入文件/从文件读出

来源:互联网 发布:软件业务需求分析 编辑:程序博客网 时间:2024/06/12 22:47

 利用NSCoding协议中的编码和解码方法进行实现对象实例的文件存储
1、过程描述:先将即将写入文件的类遵守NSCoping协议,然后在它的.m文件中添加协议中的
-(void)encodeWithCoder:(NSCoder *) aCoder编码方法和-(id)initWithCoder: (NSCoder *)aDecoder解码方法,在实现这些前提之后,就可以调用NSKeyedArchiver的archiveRootObject:(NSString *) toFile方法把对象写进指定的文件;或者调用NSKeyedUnarchiver的unarchiveObjectWithFile方法把对象从指定的文件中取出来.。
2、将一个对象存入文件所用方法剖析:
(1)编码方法。
实现NSCopying协议中的-(void)encodeWithCoder:(NSCoder *)aCoder方法,而NSCoder这个类提供了很多将各种数据类型写进文件的方法,而最常用最通用的方法是先把每个不是对象类型的成员变量通过NSNumber类或NSNumber对象的一些方法例如- (id)initWithChar:(char)value;  + (NSNumber *)numberWithInt:(int)value;  
+ (NSNumber *)numberWithDouble:(double)value;等转换为对象类型,并用aCoder调用NSCoder类的一个对象方法:- (void)encodeObject:(id)objv forKey:(NSString *)key;为每一个成员对象或封装后的成员对象分别提供一个唯一的字符串即键,一一进行编码。
(2)解码方法。实现NSCopying协议中的-(id)initWithCoder: (NSCoder *)aDecoder这个解码方法,它相当于一个初始化方法,所以要有if(self=[super init]){ // 具体实现 }语句,并且要在最后返回自身即最后添加 return self;语句。在实现语句中要用aDecoder调用NSCoder的对象方法- (id)decodeObjectForKey:(NSString *)key; 根据自己添加的键返回对应的成员对象或封装基本类型的对象。如果为封装基本数据成员类型的对象还要调用NSNumber类的一些方法如

- (char)charValue;  - (double)doubleValue;  - (int)intValue;等把自己封装的基本数据给提取出来。然后把这些对象和提取出来的数据一一赋给对应的成员变量,注意:如果对非封装基本数据类型的一些成员对象设置了retain或copy属性或以手动提供了这两种形式的set/get方法的话,在把从文件解码出来的数据(对象,基本类型)赋给这些对象成员时要调用提供的set方法进行赋值即"self.成员对象=解码出得对应对象"。就可以对对象数据进行解码提取了。            

(3)将对象写入文件的方法。利用NSKeyedArchiver类的如下类方法:
+ (BOOL)archiveRootObject:(id)rootObject toFile:(NSString *)path; 将创建好初始化过的对象写到指定的文件中,如果写入成功则返回YES,否则返回NO。
(4)从文件提取对象的方法。利用NSKeyedUnarchiver类的类方法:
+ (id)unarchiveObjectWithFile:(NSString *)path;从指定的文件读取数据赋值给一个新声明的对象名即可。

3、将多个对象存入同一个文件

(1)方式一   新建一个字典对象,为每个对象提供一个唯一的键存入这个字典对象。然后把这个字典对象利用NSKeyedArchiver类的类方法archiveRootObject:,,,toFile,,,方法写进指定的文件即可,从文件读取字典与从文件读取对象步骤相同,因为字典对象也是一个对象。具体步骤上同。

(2)方式二  新建一个NSArray数组对象,同时把多个对象存入数组。然后把数组存入指定的文件即可,从文件读取多个对象其实就是从文件读取一个存放多个对象的数组对象。具体步骤全都一样。

(3)注意事项:数组可以用快速遍历一次显示多个读出对象的内容。但字典不可以用快速遍历,但是可以用枚举进行迭代,过程如下:新建一个枚举迭代器 要利用字典对象调用它的一个对象方法objectEnumerator创建一个NSEnumerator对象假设为em,即NSEnumerator *em=[dictionary objectEnumerator]; 在用while循环结构对迭代器的

nextObject方法进行循环调用即可实现迭代。即 id temp;  while(temp=[em nextObject]){

 // 调用输出成员的方法或已经重写的description方法或者直接打印对象的成员变量值

}

4、获取系统根路径的方法:直接调用NSHomeDirectory方法即可即  NSHomeDirectory( );

5、切记:谁的事情由谁来做。主要体现如下几个方面,举例如下:

(1)继承中的初始化方法的实现;最终父类的初始化方法体内仅仅调用if(self= [super init]){// 成员变量的赋值初始化语句}实现调用继承根类NSObject的init方法对新建对象内部的isa指针赋值并判断成功赋值的情况下用初始化方法列表中的形参对自身的对应成员进行一一赋值。然而继承自父类的子类在实现初始化成员方法的时候只需要提供相应形参,然后实现时直接调用父类的初始化成员方法并把子类初始化方法的形参传入且把返回的值赋给self即可,不需要一一对继承父类的成员进行赋值。即谁的事情由谁来做,子类直接调用父类的初始化成员方法即可。

(2)组合类初始化方法和析构方法的实现。直接在包含类的初始化方法体内调用成员对象所属类的初始化方法并把自身初始化方法的形参作为成员对象初始化方法列表中对应实参进行赋值即可,不必一一对成员对象的实例变量一一赋值。再者因为成员对象是包含类的成员,所以要由包含类的dealloc方法进行销毁,只需要在包含类中重写dealloc方法并在方法体内调用成员对象的release方法进行释放,再加上[super dealloc]即可。即谁的事情由谁来做。

(3)继承中copyWithZone方法的实现 。只有父类实现了copy机制的方法,继承父类的子类实现了copy方法才会有效,因为拷贝子类时自动调用子类的copyWithZone方法过程中会自动调用父类的copyWithZone方法。即谁的事谁做

(4)组合类copyWithZone方法的实现。必须让包含类的对象成员所属的对象实现copyWithZone方法,然后在实现包含类的copyWithZone方法的过程中既可以直接调用包含类的初始化成员方法创建新对象,也可以在创建新对象之后调用成员的copy方法进行对新对象的成员对象的赋值操作。

(5)继承中编码方法与解码方法的实现:父类与子类都必须实现编码方法与解码方法。

(6)组合类编码方法与解码方法的实现:成员对象所属的类和包含类都必须实现编码方法与解码方法。

注意:在赋值操作中,只要是对象成员的赋值操作(一般都为对象成员设置了自动提供set/get方法的retain或copy属性),必须直接用self.调用调用成员对象的set方法进行赋值(特别是解码的赋值过程中),不然有时会出错。

代码验证,实例如下:

创建遵守了NSCopying协议的Baby类

编辑Baby.h如下:

////  Baby.h//  file////  Created by apple on 15/8/21.//  Copyright (c) 2015年 liu. All rights reserved.//#import <Foundation/Foundation.h>@interface Baby : NSObject<NSCoding>@property (nonatomic,assign) int age;@property (nonatomic,retain) NSString *name;@property (nonatomic,assign) double score;-(id)initWithAge:(int) a  andName:(NSString *) n andScore:(double) s ;-(void)print;@end

编辑Baby.m文件如下:

////  Baby.m//  file////  Created by apple on 15/8/21.//  Copyright (c) 2015年 liu. All rights reserved.//#import "Baby.h"@implementation Baby-(id)initWithAge:(int) a andName:(NSString *) n andScore:(double) s{    if (self=[super init]) {        _age=a;        self.name=n;        _score=s;    }    return  self;}-(void)print{    NSLog(@"age=%d, name= %@, score=%.2lf",_age, _name, _score);}-(void)encodeWithCoder:(NSCoder *)aCoder{    [aCoder encodeObject:[NSNumber numberWithInt:_age] forKey:@"1"];    [aCoder encodeObject:_name forKey:@"2"];    [aCoder encodeObject:[NSNumber numberWithDouble:_score] forKey:@"3"];}-(id)initWithCoder:(NSCoder *)aDecoder{    if (self = [super init]) {        _age=[[aDecoder decodeObjectForKey:@"1"] intValue];        self.name=[aDecoder decodeObjectForKey:@"2"];        _score=[[aDecoder decodeObjectForKey:@"3"] doubleValue];    }    return self;}-(NSString *)description{  // 为类重写description方法,相当于Java中的toString方法,当打印类的对象时会自动调用此方法    NSString *t=[NSString stringWithFormat:@"age=%d, name=%@, score=%.2lf",_age,_name,_score];    return t;}-(void)dealloc{    [_name release];    [super dealloc];}@end
 编辑main.m文件如下:

////  main.m//  file////  Created by apple on 15/8/21.//  Copyright (c) 2015年 liu. All rights reserved.//#import <Foundation/Foundation.h>#import "Baby.h"void Test1(){//  将单个对象写入到指定文件中    Baby *b = [[Baby alloc] initWithAge:12 andName:@"wangQi" andScore:98.8];        NSString *pathDirectory = [NSString stringWithFormat:@"%@/Documents/ff.txt",NSHomeDirectory()];        //  归档类:把对象b归档到此文件中去(此时系统会自动调用归档中的方法)    if([NSKeyedArchiver archiveRootObject:b toFile:pathDirectory]){//写入文件        NSLog(@"单个对象成功写入文件!!!");    }        NSLog(@"从单个对象文件中读出数据.......");    // 解档类:把对象b1从此文件中取出(此时系统会自动调用协议中的解档方法)    Baby *b1=[NSKeyedUnarchiver unarchiveObjectWithFile:pathDirectory]; //读出文件    [b1 print];    NSLog(@"-------------------------------------");}void Test2(){//  将多个对象通过字典写入同一文件    Baby *bb1 = [[Baby alloc] initWithAge:1 andName:@"张云" andScore:30];    Baby *bb2 = [[Baby alloc] initWithAge:2 andName:@"李东" andScore:60];    Baby *bb3 = [[Baby alloc] initWithAge:3 andName:@"王八" andScore:90];    NSString *path=[NSString stringWithFormat:@"%@/Documents/dic.txt",NSHomeDirectory()];    NSDictionary *dict=@{@"a": bb1,@"b":bb2 ,@"c":bb3};    if ([NSKeyedArchiver archiveRootObject:dict toFile:path]) {        NSLog(@"字典成功写入文件!!!");    }    NSLog(@"从字典文件中读出数据........");    NSDictionary *dict2=[NSKeyedUnarchiver unarchiveObjectWithFile:path]; // 读出文件    NSEnumerator *em=[dict2 objectEnumerator]; // 枚举字典    id temp;    while ( temp=[em nextObject]) {        // 调用对象的输出方法输出成员内容或为类重写description方法       // [temp print];        NSLog(@"%@",temp);    }        //  根据键获取对象    id t=[dict2 objectForKey:@"b"];    [t print];    NSLog(@"-------------------------------------");}void Test3(){ // 将多个对象通过数组写入同一个文件    Baby *bb1=[[Baby alloc] initWithAge:1 andName:@"张三三" andScore:300];    Baby *bb2=[[Baby alloc] initWithAge:2 andName:@"李四四" andScore:600];    Baby *bb3=[[Baby alloc] initWithAge:3 andName:@"王五五" andScore:900];    NSArray *array=@[bb1,bb2,bb3];    NSString *path=[NSString stringWithFormat:@"%@/Desktop/1.txt",NSHomeDirectory()];    if ([NSKeyedArchiver archiveRootObject:array toFile:path]) {// 写入文件        NSLog(@"数组成功写入文件!!!");    }    NSLog(@"从数组文件中读出数据如下........");    NSArray *array2=[NSKeyedUnarchiver unarchiveObjectWithFile:path]; // 读出文件    for(id obj in array2){       // [obj print];        NSLog(@"%@",obj);    }    NSLog(@"-------------------------------------");}int main(int argc, const char * argv[]){    @autoreleasepool {       Test1();       Test2();       Test3();    }    return 0;}
运行结果如下:



----------------------------------------------------------------------------------------------------------------------------------------------------------

代码验证,项目二:要求如下

1、定义一个Computer类
实例变量:float width; NSString *name;
方法:一个带两个参数的初始化函数;
print()函数;
dealloc()函数;
2、 定义一个Person类
实例变量:NSString *name; Computer *c; int age;
方法:一个带三个参数的初始化函数;
print()函数;
dealloc()函数;
要求:用该类创建出来的对象能实现copy和存入文件。
3、 主函数要求:
a、分别创建Computer类的对象cc和Person类对象pp;并输出对象信息。
b、利用copy函数创建Person类对象p1; 并输出对象信息
c、把pp存入文件hello.txt中,文件目录为Documents目录。
d、从文件hello.txt中读取对象p2, 并输出对象信息。
e、不能出现内存泄漏和多次删除。

代码实例,编辑如下:

新建Computer类,编辑Computer.h如下

////  Computer.h//  Computer////  Created by apple on 15/8/22.//  Copyright (c) 2015年 liu. All rights reserved.//#import <Foundation/Foundation.h>@interface Computer : NSObject<NSCoding,NSCopying>{float width;    NSString * name;}@property float width;@property (nonatomic,retain) NSString * name;-(id) initWithWidth:(float)_width  andName:(NSString *) _name;-(void) print;@end
编辑Computer.m如下:

////  Computer.m//  Computer////  Created by apple on 15/8/22.//  Copyright (c) 2015年 liu. All rights reserved.//#import "Computer.h"@implementation Computer@synthesize  width,name;-(id) initWithWidth:(float)_width  andName:(NSString *) _name{    if (self = [super init]) {        width =  _width;        self.name =  _name;    }    return  self;}-(void) print{    NSLog(@"width=%f name=%@",width,self.name);}-(void)dealloc{    [name release];    [super dealloc];}-(void) encodeWithCoder:(NSCoder *)aCoder{    [aCoder encodeObject:name forKey:@"2"];    [aCoder encodeObject:[NSNumber numberWithFloat:width] forKey:@"1"];}-(id)initWithCoder:(NSCoder *)aDecoder{    if(self = [super init])    {        width = [[aDecoder decodeObjectForKey:@"1"] floatValue];       self.name = [aDecoder decodeObjectForKey:@"2"];    }    return  self;}-(id)copyWithZone:(NSZone *)zone{    Computer *newCom = [[Computer allocWithZone:zone] initWithWidth:width andName:name];    return  newCom;}@end
新建Person类编辑Person.h如下:

////  Person.h//  Computer////  Created by apple on 15/8/22.//  Copyright (c) 2015年 liu. All rights reserved.//#import <Foundation/Foundation.h>#import "Computer.h"@interface Person : NSObject<NSCopying,NSCoding>{    NSString *name;    Computer *c;    int age;}@property (nonatomic,retain) Computer * c;@property (nonatomic,retain) NSString *name;@property int age;-(id)initWithName:(NSString *)_name andAge:(int) _age andComputer:(Computer *)_Computer;-(void) print;@end
编辑Person.m如下:

////  Person.m//  Computer////  Created by apple on 15/8/22.//  Copyright (c) 2015年 liu. All rights reserved.//#import "Person.h"@implementation Person@synthesize name,age,c;-(id)initWithName:(NSString *)_name andAge:(int) _age andComputer:(Computer *)_Computer{    if(self=[super init]) {        self.c = _Computer;        self.name = _name;        self.age =  _age;    }    return  self;}-(void) print{    [c print];    NSLog(@"Name=%@ age=%d",self.name,self.age);}-(void)dealloc{    [name release];    [c release];    [super dealloc];}-(id)copyWithZone:(NSZone *)zone{    Person *per = [[Person allocWithZone:zone] initWithName:name andAge:age andComputer:self.c];    return per;}-(id)initWithCoder:(NSCoder *)aDecoder{    if(self = [super init]){    age = [[aDecoder  decodeObjectForKey:@"1" ] intValue];  self.name = [aDecoder  decodeObjectForKey:@"2" ];   self.c = [aDecoder  decodeObjectForKey:@"3" ];    }    return self;}-(void)encodeWithCoder:(NSCoder *)aCoder{    [aCoder encodeObject:[NSNumber numberWithInt:age] forKey:@"1"];    [aCoder encodeObject:name forKey:@"2"];    [aCoder encodeObject:c forKey:@"3"];}@end
在main.m中调用实现,代码如下:

////  main.m//  Computer////  Created by apple on 15/8/22.//  Copyright (c) 2015年 liu. All rights reserved.//#import <Foundation/Foundation.h>#include "Person.h"int main(int argc, const char * argv[]){    @autoreleasepool {        Computer *cc = [[Computer alloc] initWithWidth:24.3 andName:@"lixnxinag"];        Person *pp = [[Person alloc] initWithName:@"liuxun" andAge:22 andComputer:cc];        [cc print];        [pp print];        Person *p1= [ pp copy];        [p1  print];        if([NSKeyedArchiver archiveRootObject:pp toFile:@"/Users/apple/Desktop/aa.txt"])        {            NSLog(@"写入成功");        }        Person *p2 = [NSKeyedUnarchiver unarchiveObjectWithFile:@"/Users/apple/Desktop/aa.txt"];        [p2 print];        [cc release];        [pp release];    }    return 0;}
运行结果如下:







0 0