ObjC学习11-复制对象与归档

来源:互联网 发布:孙悟空kingking淘宝店 编辑:程序博客网 时间:2024/06/06 19:27

感觉这两个概念有点朦胧,为了学习路线的完整性,这里浅浅地学习下,不懂的以后实践再去想懂~ 


1.复制对象

Foundation类实现了名为copy和mutableCopy的方法 可以用这些方法来创建对象的副本。

代码实例:

 NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];    //NSLog(@"1326");    NSMutableArray *dArray = [NSMutableArray arrayWithObjects:@"a",@"b",@"c",@"d",nil];    NSMutableArray *dArray2 ;    dArray2 = dArray;    [dArray2 removeObjectAtIndex:0];    NSLog(@"dArray:");    for(NSString *elem in dArray)    {        NSLog(@"%@",elem);    }     NSLog(@"dArray2:");    for(NSString *elem2 in dArray2)    {        NSLog(@"%@",elem2);    }    dArray2 = [dataArray mutableCopy];       [dArray2 removeObjectAtIndex:0];    NSLog(@"dArray:");    for(NSString *elem in dArray)    {        NSLog(@"%@",elem);    }     NSLog(@"dArray2:");    for(NSString *elem2 in dArray2)    {        NSLog(@"%@",elem2);    }    [pool drain];
在win下的开发环境编译出错,这个错误暂时没解决,代码逻辑上是没错的,有时间再xcode下去跑一遍,

结果是:赋值的数组传的是指针引用 remove后 双方原先的索引0的字符串没有了,而赋值的数组将是以对象的形式存在于dArray2,删除索引0而不影响到原数组。

此外还可以通过实现<NSCopying>及<NSMutableCopying>协议来实现复制对象。

如:@interface F:NSObject<NSCopying>  你们F.m中就必须添加方法 -(id) copyWith:(NSzone*) zone{...}

还可以用复制方法和取值方法复制对象:只要实现复制方法或是取值方法,都应考虑变量中存储的内容、要检索的内容以及时候需要保护这些值。

-(void) setName:(NSString *)theName{name = [theName copy];}//当然,要使赋值方法的内存管理更友好一些,首先应该释放旧的值-(void) setName:(NSString *)theName{[name autorelease];name = [theName copy];}
//property声明@property (nonatomic,copy) NSString *name;//会生成一个合并的方法,其类型类似于:-(void) setName :(NSString *) theName{ if(theName!=name) {    [name = release];    name = [theName copy];}
这里使用nonatomic(默认是atomic)是为了告诉系统不要使用mutex(互斥)锁定保护属性存取器方法这种方法会在设置新值时释放变量的旧值,确保旧的值不会被销毁。如果在多线程环境中运行,需要考虑使用atomic存取器方法。

简单总结就是赋值的实例变量实际是原变量的引用,而复制的对象变量是它的完整副本。


2.归档

归档是指用某种个性来保存一个或多个对象,以便以后还原这些对象的过程。(类似序列化~)

2.1使用XML属性列表进行归档 以key -value键值对写入文件

  NSDictionary *glossary=[NSDictionary dictionaryWithObjectsAndKeys: @"a",@"aaa",@"b",@"bbb",@"c",@"ccc",nil];    if([glossary writeToFile:@"glossary"atomically:YES]==NO)    {    NSLog(@"save failed!");    }

atomically:YES这里是为字典写入文件创建一个glossary临时备份文件,若一旦成功将把数据转移到名为glossary的指定文件中。

在win开发环境下最后生成的程序文件不是XML文件这点等在xcode下再测一遍=.=

要将文件中的内容读入程序,可以用dictionaryWithContentsOfFile:或arrayWithContentsOfFile:方法。读回数据可使用dataWithContentsOfFile:,读回字符串对象可使用stringWithContentsOfFile:方法。

   NSDictionary *g;    g= [NSDictionary dictionaryWithContentsOfFile :@"glossary"];    for(NSString *k in g)    {        NSLog(@"%@:%@",[g objectForKey:k]);    }
2.2使用NSKeyedArchiver归档 以带键key的文档把对象存入文件中

在IPhone中使用归档功能必须使用NSKeyedArchiver<Foundation/NSKeyedArchiver.h>

   NSDictionary *glossary=[NSDictionary dictionaryWithObjectsAndKeys: @"aa",@"aaa",@"bb",@"bbb",@"cc",@"ccc",nil];    [NSKeyedArchiver archiveRootObject:glossary toFile:@"glossary.archive"];
把字典对象归档到当前目录下,也可以通过NSKeyedUnarchiver的unArchiveObjectWithFile:方法把创建的归档读入程序中。

   NSDictionary *glossary;     glossary=[NSKeyedUnarchiver unArchiveObjectWithFile:@"glossary.archive"];
在辉旭glossary后,程序可以通过枚举祺内容来验证恢复是否成功~

2.3编码和解码

通常自定义类对象不能直接归档,必须告知系统如何归档(或编码)你的对象,以及如何解归档(解码)它们。必须遵守<NSCoding>协议,在类定义中添加encodeWithCoder: 方法和initWithCoder: 方法以实现归档对象和恢复对象

在带键的档案中编码和解码基本数据类型:


编码方法

解码方法

encodeBool: forKey

decodeBool: forKey

encodeInt:  forKey

decodeInt:  forKey

encodeInt31: forKey

decodeInt32: forKey

encodeInt64: forKey

decodeInt64: forKey

encodeFloat: forKey

decodeFloat: forKey

encodeDouble: forKey

decodeDouble: forKey

对于基本的Objective-C类,可以使用
encodeObject:forKey:和decodeObjectforKey:编码和解

//基本的Objective-C类编码和解码示例:
//Addresscard.h Interface File#import <Foundation/Foundation.h>@interface AddressCard : NSObject<NSCopying,NSCoding> {NSString *name;NSString *email;}@property (nonatomic, copy) NSString *name, *email;-(void) setName: (NSString *) theNameandEmail: (NSString *) theEmail;-(void) retainName: (NSString *) theNameandEmail: (NSString *) theEmail;-(NSComparisonResult) compareNames: (id) element;-(void) print;@end#import "AddressCard.h"@implementation AddressCard@synthesize name, email;-(void) setName: (NSString *) theNameandEmail: (NSString *) theEmail{[self setName: theName];[self setEmail: theEmail];}// Compare the two names from the specified address cards-(NSComparisonResult) compareNames: (id) element{return [name compare: [element name]];}-(void) print{NSLog (@"====================================");NSLog (@"| |");NSLog (@"| %-31s |", [name UTF8String]);NSLog (@"| %-31s |", [email UTF8String]);NSLog (@"| |");NSLog (@"| |");NSLog (@"| |");NSLog (@"| O O |");NSLog (@"====================================");}-(AddressCard *) copyWithZone: (NSZone *) zone{AddressCard *newCard = [[AddressCardallocWithZone: zone] init];    [newCardretainName: name andEmail: email];    return newCard;}-(void) retainName: (NSString *) theNameandEmail: (NSString *) theEmail{    name = [theName retain];    email = [theEmail retain];}-(void) encodeWithCoder: (NSCoder *) encoder{    [encoder encodeObject: name forKey: @"AddressCardName"];    [encoder encodeObject: email forKey: @"AddressCardEmail"];}-(id) initWithCoder: (NSCoder *) decoder{    name = [[decoder decodeObjectForKey: @"AddressCardName"] retain];    email = [[decoder decodeObjectForKey: @"AddressCardEmail"] retain];    return self;}-(void) dealloc{    [name release];    [email release];    [super dealloc];}@end

#import "AddressCard.h"@interface AddressBook: NSObject<NSCopying,NSCoding>{NSString *bookName;NSMutableArray *book;}@property (nonatomic, copy) NSString *bookName;@property (nonatomic, copy) NSMutableArray *book;-(id) initWithName: (NSString *) name;-(void) sort;-(void) addCard: (AddressCard *) theCard;-(void) removeCard: (AddressCard *) theCard;-(int) entries;-(void) list;-(AddressCard *) lookup: (NSString *) theName;-(void) dealloc;@end#import "AddressBook.h"@implementation AddressBook@synthesize book, bookName;// set up the AddressBook’s name and an empty book-(id) initWithName: (NSString *) name{self = [super init];if (self) {bookName = [[NSStringalloc] initWithString: name];book = [[NSMutableArrayalloc] init];}return self;}-(void) sort{[book sortUsingSelector: @selector(compareNames:)];}-(void) addCard: (AddressCard *) theCard{[book addObject: theCard];}-(void) removeCard: (AddressCard *) theCard{[book removeObjectIdenticalTo: theCard];}-(int) entries{return [book count];}-(void) list{NSLog (@"======== Contents of: %@ =========", bookName);for ( AddressCard *theCard in book )NSLog (@"%-20s %-32s", [theCard.name UTF8String],[theCard.email UTF8String]);NSLog (@"==================================================");}// lookup address card by name — assumes an exact match-(AddressCard *) lookup: (NSString *) theName{for ( AddressCard *nextCard in book )if ( [[nextCard name] caseInsensitiveCompare: theName] == NSOrderedSame )return nextCard;return nil;}-(void) dealloc{[bookName release];[book release];[super dealloc];}-(void) encodeWithCoder: (NSCoder *) encoder{[encoder encodeObject:bookNameforKey:@"AddressBookBookName"];[encoder encodeObject:bookforKey: @"AddressBookBook"];}-(id) initWithCoder: (NSCoder *) decoder{bookName     = [[decoder decodeObjectForKey: @"AddressBookBookName"] retain];book     = [[decoder decodeObjectForKey: @"AddressBookBook"] retain];return self;}// Method for NSCopying protocol-(id) copyWithZone: (NSZone *) zone{AddressBook *newBook = [[self class] allocWithZone: zone];    [newBookinitWithName: bookName];    [newBooksetBook: book];    return newBook;}@end
实现:
#import "AddressBook.h"#import <Foundation/NSAutoreleasePool.h>int main (intargc, char *argv[]){NSString *aName = @"Julia Kochan";NSString *aEmail = @"jewls337@axlc.com";NSString *bName = @"Tony Iannino";NSString *bEmail = @"tony.iannino@techfitness.com";NSString *cName = @"Stephen Kochan";NSString *cEmail = @"steve@steve_kochan.com";NSString *dName = @"Jamie Baker";NSString *dEmail = @"jbaker@hitmail.com";NSAutoreleasePool * pool = [[NSAutoreleasePoolalloc] init];AddressCard *card1 = [[AddressCardalloc] init];AddressCard *card2 = [[AddressCardalloc] init];AddressCard *card3 = [[AddressCardalloc] init];AddressCard *card4 = [[AddressCardalloc] init];AddressBook *myBook = [AddressBookalloc];// First set up four address cards[card1 setName: aNameandEmail: aEmail];[card2 setName: bNameandEmail: bEmail];[card3 setName: cNameandEmail: cEmail];[card4 setName: dNameandEmail: dEmail];myBook = [myBookinitWithName: @"Steve’s Address Book"];// Add some cards to the address book[myBookaddCard: card1];[myBookaddCard: card2];[myBookaddCard: card3];[myBookaddCard: card4];[myBook sort];if ([NSKeyedArchiverarchiveRootObject: myBooktoFile: @"addrbook.arch"]  == NO)NSLog (@"archiving failed");[card1 release];[card2 release];[card3 release];[card4 release];[myBook release];[pool drain];return 0;}// Addresscard.h Interface File 对AddressBook解码#import "AddressBook.h"#import <Foundation/NSAutoreleasePool.h>int main (intargc, char *argv[]){AddressBook *myBook;NSAutoreleasePool * pool = [[NSAutoreleasePoolalloc] init];myBook = [NSKeyedUnarchiverunarchiveObjectWithFile:  @"addrbook.arch"];[myBook list];[pool drain];return 0;}

输出:
======== Contents of: Steve’s Address Book =========
Jamie Baker jbaker@hitmail.com
Julia Kochan jewls337@axlc.com
Stephen Kochan steve@steve_kochan.com
Tony Iannino tony.iannino@techfitness.com
====================================================
在解码地址簿过程中,自动调用向两个类添加的解码方法。

encodeObject:forKey:方法 
内置类行数据编码示例
@interface Foo: NSObject<NSCoding>{NSString *strVal;intintVal;    float floatVal;}@property (copy, nonatomic) NSString *strVal;@property intintVal;@property float floatVal;@end@implementation Foo@synthesize strVal, intVal, floatVal;-(void) encodeWithCoder: (NSCoder *) encoder{   //对每个实例变量编码 归档对象的三个实例变量    [encoder encodeObject: strValforKey: @”FoostrVal”];    [encoder encodeInt: intVal forKey: @”FoointVal”];    [encoder encodeFloat: floatValforKey: @”FoofloatVal”];}-(id) initWithCoder: (NSCoder *) decoder{   //解码每个实例变量strVal = [[decoder decodeObjectForKey: @”FoostrVal”] retain];intVal = [decoder decodeIntForKey: @”FoointVal”];floatVal = [decoder decodeFloatForKey: @”FoofloatVal”];    return self;}@end
#import <Foundation/NSObject.h>#import <Foundation/NSString.h>#import <Foundation/NSKeyedArchiver.h>#import <Foundation/NSAutoreleasePool.h>#import “Foo.h” // Definition for our Foo classint main (intargc, char *argv[]){NSAutoreleasePool * pool = [[NSAutoreleasePoolalloc] init];Foo *myFoo1 = [[Fooalloc] init];  Foo *myFoo2;[myFoo1 setStrVal: @”This is the string”];[myFoo1 setIntVal: 12345];[myFoo1 setFloatVal: 98.6];[NSKeyedArchiverarchiveRootObject: myFoo1 toFile: @”foo.arch”];myFoo2 = [NSKeyedUnarchiverunarchiveObjectWithFile: @”foo.arch”];NSLog (@”%@\n%i\n%g”, [myFoo2 strVal], [myFoo2 intVal], [myFoo2 floatVal]);[myFoo1 release];[pool drain];return 0;}

结果:
This is the string
12345
98.6


2.4使用NSData创建自定义归档 (NSData数据流对象类)
比如想手机一些或全部对象,并将其存储到单个档案文件中,可以使用自定义归档
代码实例:
//归档#import <Foundation/NSObject.h>#import <Foundation/NSAutoreleasePool.h>#import <Foundation/NSString.h>#import <Foundation/NSKeyedArchiver.h>#import <Foundation/NSCoder.h>#import <Foundation/NSData.h>#import "AddressBook.h"#import "Foo.h"int main (intargc, char *argv[]){NSAutoreleasePool * pool = [[NSAutoreleasePoolalloc] init];Foo *myFoo1 = [[Fooalloc] init];Foo *myFoo2;NSMutableData *dataArea;NSKeyedArchiver *archiver;AddressBook *myBook;// in myBook containing four address cards    [myFoo1 setStrVal: @"This is the string"];    [myFoo1 setIntVal: 12345];    [myFoo1 setFloatVal: 98.6];// Set up a data area and connect it to an NSKeyedArchiver objectdataArea = [NSMutableData data];archiver = [[NSKeyedArchiveralloc]initForWritingWithMutableData: dataArea];// Now we can begin to archive objects    [archiverencodeObject: myBookforKey: @"myaddrbook"];    [archiverencodeObject: myFoo1 forKey: @"myfoo1"];    [archiverfinishEncoding];// Write the archived data  to a file    if ( [dataAreawriteToFile: @"myArchive" atomically: YES] == NO)NSLog (@"Archiving failed!");    [archiver release];    [myFoo1 release];    [pool drain];    return 0;}

//解码#import <Foundation/NSObject.h>#import <Foundation/NSAutoreleasePool.h>#import <Foundation/NSString.h>#import <Foundation/NSKeyedArchiver.h>#import <Foundation/NSCoder.h>#import <Foundation/NSData.h>#import "AddressBook.h"#import "Foo.h"int main (intargc, char *argv[]){NSAutoreleasePool * pool = [[NSAutoreleasePoolalloc] init];NSData *dataArea;NSKeyedUnarchiver *unarchiver;Foo *myFoo1;AddressBook *myBook;    // Read in the archive and connect an    // NSKeyedUnarchiver object to itdataArea = [NSDatadataWithContentsOfFile: @"myArchive"];if (! dataArea) {NSLog (@"Can’t read back archive file! "); return (1);}unarchiver = [[NSKeyedUnarchiveralloc] initForReadingWithData: dataArea];// Decode the objects we previously stored in the archivemyBook = [unarchiverdecodeObjectForKey: @"myaddrbook"];myFoo1 = [unarchiverdecodeObjectForKey: @"myfoo1"];[unarchiverfinishDecoding];[unarchiver release];// Verify that the restore was successful[myBook list];NSLog(@"%@\n%i\n%g", [myFoo1 strVal],[myFoo1 intVal], [myFoo1 floatVal]);[pool release];return 0;}

输出:
======== Contents of: Steve’s Address Book =========
Jamie Baker jbaker@hitmail.com
Julia Kochan jewls337@axlc.com
Stephen Kochan steve@steve_kochan.com
Tony Iannino tony.iannino@techfitness.com
===================================================
This is the string
12345
98.6

如果把地址簿和Foo对象成功解码,也就会输出以上结果咯~

2.5使用归档程序复制对象:深复制 (难道是反射?)
前面对象复制对可变字符串元素创建了对象副本,然而实际上是没有复制字符串本身,只是复制对他们的引用。
这里可以使用Foundation的归档能力来创建对象的深复制。例如:可以通兑dataArray归档到一个缓冲区,然后把它接档,将结果指派到dataArray2,这个过程不需要使用文件,归档和解档都可以再内存中发生。
#import <Foundation/NSObject.h>#import <Foundation/NSAutoreleasePool.h>#import <Foundation/NSString.h>#import <Foundation/NSKeyedArchiver.h>#import <Foundation/NSArray.h>int main (intargc, char *argv[]){NSAutoreleasePool *pool = [[NSAutoreleasePoolalloc] init];NSData *data;NSMutableArray *dataArray = [NSMutableArrayarrayWithObjects:    [NSMutableStringstringWithString: @"one"],    [NSMutableStringstringWithString: @"two"],    [NSMutableStringstringWithString: @"three"],    nil    ];NSMutableArray *dataArray2;NSMutableString *mStr;    // Make a deep copy using the archiver    data = [NSKeyedArchiverarchivedDataWithRootObject: dataArray];    dataArray2 = [NSKeyedUnarchiverunarchiveObjectWithData: data]; mStr = [dataArray2 objectAtIndex: 0];    [mStrappendString: @"ONE"];NSLog (@"dataArray: ");    for ( NSString *elem in dataArray )NSLog ("%@", elem);NSLog (@"\ndataArray2: ");    for ( NSString *elem in dataArray2 )NSLog ("%@", elem);    [pool drain];    return 0;}

结果:
dataArray:
one
two
three
dataArray2:
oneONE
two
three


----------------------------
NICE, 把复制对象和归档的内容了解完了,那么Objc的基础知识学习也就告一段落啦~微笑

原创粉丝点击