您的位置:首页 > 移动开发 > IOS开发

ios 深度复制 copy & mutablecopy

2015-10-08 21:00 471 查看
首先讲一下

copy 遵守NSCopying,并且实现 copyWithZone: 方法; 可以copy一个对象(OC已实现类,返回的是不可变对象,即使是NSMutableString和NSMutableArray,返回值 是NSString和NSArray这种)。

mutableCopy 遵守NSMutableCopying,并且实现 mutableCopyWithZone: 方法 可以mutableCopy一个对象 (NSMutableString返回是 NSMutableString)。

注意的一点是,不管是mutableCopy 还是 copy ,如果是NSArray里面的元素是对象的引用,那么复制出来的仍旧是引用。(简单的想,有一个数组A,里面的值是地址0x123,那么copy出来的数组,对应的值应该还是0x123.而0x123对应着一个对象的地址)

那怎么做深度复制,把地址0x123对应的内存也复制过去?

回想下,NSUserDefaults存放的数组,数组里面的对象的值,和 下次加载的时候对象的值是一样的,但是内存的地址是完全不一样的。

那么,这样可以做到,完全复制!


NSArray* newArr = [NSKeyedUnarchiver unarchiveObjectWithData:[NSKeyedArchiver archivedDataWithRootObject: array]];
其实就是一个序列化的过程。

接下来,如果copy 或者 序列化的容器类或者对象类里面,含有自定义的类的时候,应该怎么办?

1,copy 的问题。
CustomClass 要实现 NSCopying 协议。

- (id)copyWithZone:(NSZone *)zone;

在上面的方法中,增加初始化和复制的过程。

相当于 A = [B copy];调用的过程中,B会调用copyWithZone的函数,然后用自身的数据去分配和初始化 一个新的类,然后把这个类作为返回值Bnew, A = Bnew;

2,序列化的问题。

CustomClass 要实现 NSCoding 协议。

在- (void)encodeWithCoder:(NSCoder *)coder 函数中,把属性值一个个调用[coder encodeObject:tempValue forKey:propertyName];

在- (instancetype)initWithCoder:(NSCoder *)aDecoder 函数中,把属性值一个个[self setValue:[aDecoder decodeObjectForKey:propertyName] forKey:propertyName];

这个两步都是一个繁琐的过程。

然后就想一劳永逸下:

@interface LYCoding : NSObject <NSCoding, NSCopying>

@end

@implementation LYCoding

- (id)copyWithZone:(NSZone *)zone

{

id ret = [[[self class] allocWithZone:zone] init];

unsigned int propertyCount = 0;

objc_property_t * properties = class_copyPropertyList( [self class], &propertyCount );

for ( NSUInteger i = 0; i < propertyCount; i++ )

{

const char * name = property_getName(properties[i]);

NSString * propertyName = [NSString stringWithCString:name encoding:NSUTF8StringEncoding];

NSObject<NSCopying> * tempValue = [self valueForKey:propertyName];

if (tempValue) {

id value = [tempValue copy];

[ret setValue:value forKey:propertyName];

}

}

return ret;

}

- (void)encodeWithCoder:(NSCoder *)coder

{

unsigned int propertyCount = 0;

objc_property_t * properties = class_copyPropertyList( [self class], &propertyCount );

for ( NSUInteger i = 0; i < propertyCount; i++ )

{

const char * name = property_getName(properties[i]);

NSString * propertyName = [NSString stringWithCString:name encoding:NSUTF8StringEncoding];

NSObject * tempValue = [self valueForKey:propertyName];

// [tempValue conformsToProtocol:@protocol(NSCoding)];

[coder encodeObject:tempValue forKey:propertyName];

}

}

- (instancetype)initWithCoder:(NSCoder *)aDecoder

{

if (self = [super init]) {

unsigned int propertyCount = 0;

objc_property_t * properties = class_copyPropertyList( [self class], &propertyCount );

for ( NSUInteger i = 0; i < propertyCount; i++ )

{

const char * name = property_getName(properties[i]);

NSString * propertyName = [NSString stringWithCString:name encoding:NSUTF8StringEncoding];

[self setValue:[aDecoder decodeObjectForKey:propertyName] forKey:propertyName];

}

}

return self;

}

@end

这个是我自定义的基类,实现copy 和 coding的协议。新的类如果需要就直接继承这个类。

[tempValue conformsToProtocol:@protocol(NSCoding)];

这一行代码有什么用?

因为这个类还不完善,如果CustomA类中,有一个属性值是CustomB类。

那么需要在encode A类的时候,判断下每个值 的属性,是否实现了NSCoding,如果是,那么把它序列化成NSData.(NSData *personEncodedObject = [NSKeyedArchiver archivedDataWithRootObject:item];)

因为在这个项目,还用不到这个东西,所以就没加上去。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: