ios 深度复制 copy & mutablecopy

首先讲一下
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];)

 

因为在这个项目,还用不到这个东西,所以就没加上去。 

 

posted on 2015-10-08 21:00  loying  阅读(1372)  评论(0编辑  收藏  举报

导航