`
xuela_net
  • 浏览: 489218 次
文章分类
社区版块
存档分类
最新评论

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

 
阅读更多

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


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 class
int 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 object
dataArea = [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 it
dataArea = [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 archive
myBook = [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的基础知识学习也就告一段落啦~微笑

分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics