浅析Objective-C的copy

一直对NSObject的copy方法似懂非懂,今天工做作完了,整理一下html

深复制和浅复制是什么在这里就不赘述api

今天主要分三种类型对copy进行探讨:系统非容器类对象、系统容器类对象和自定义对象app

系统非容器类对象(NSString,NSNumber等)

NSString *str1 = @"123";
NSString *str2 = [str1 copy];
NSString *str3 = [str1 mutableCopy];
NSMutableString *str4 = [str1 copy];
NSMutableString *str5 = [str1 mutableCopy];
//    [str3 appendString:@"456"];   //编译出错
//    [str4 appendString:@"456"];   //运行出错

如上代码,打印结果以下图ide

 

结论:atom

1.对比全部string的地址,发现copy返回的是浅复制(只复制了指针),mutableCopy返回的是深复制(从新分配了内存)spa

2.str3在编译时为NSString,运行时为NSMutableString类型,从图中str3的类型为__NSCFString可证实,因此修改操做在编译的时候就会报错指针

3.str4在编译时为NSMutableString,运行时为NSString类型,从图中str4的类型为__NSCFConstantString可证实。因此对str4进行append等修改,编译可经过,但运行时会直接crashcode

 

系统容器类对象(NSArray,NSDictionary等)

NSArray *array1 = [NSArray arrayWithObjects:[NSMutableString stringWithString:@"1"], @"2", nil];
NSArray *array2 = [array1 copy];
NSArray *array3 = [array1 mutableCopy];
NSMutableArray *array4 = [array1 copy];
NSMutableArray *array5 = [array1 mutableCopy];

结论:htm

array1-array5的原理同NSString部分,可是注意mutableCopy返回的深复制,是对容器的深复制,容器里的元素仍然是浅复制对象

 

疑问:那如何对容器内的元素也进行深复制呢?

第一种方法:使用initWithArray:copyItems:方法

NSArray *array1 = [NSArray arrayWithObjects:[NSMutableString stringWithString:@"1"], @"2", nil];
NSArray *array6 = [[NSArray alloc] initWithArray:array1 copyItems:YES];

 

此时array6的第一个元素是array1的第一个元素的深复制,可是第二个元素则是浅复制。

莫非用官方的api也会出错?其实不是的,由于对于不可变对象,对其进行浅复制就足够,由于你改变不了其值!

因此initWithArray:copyItems:能够实现一种不够完全的深复制

疑问:若是真的须要对容器中的不可变对象进行深复制,那怎么办?

第二种方法:使用NSKeyedUnarchiver

NSArray *array7 = [NSKeyedUnarchiver unarchiveObjectWithData:[NSKeyedArchiver archivedDataWithRootObject:array1]];

 

NSKeyedUnarchiver是真正意义上的深复制

 

自定义对象

 以上,NSString和NSArray都是默认实现了NSCopying和NSMutableCopying协议,才能响应copy和mutableCopy方法

若是是自定义对象,那么怎么让其响应copy和mutableCopy方法呢?

上代码

//
//  MyObj.h
//  No
//
//  Created by Norcy on 16/1/28.
//  Copyright © 2016年 Norcy. All rights reserved.
//

#import <Foundation/Foundation.h>

@interface MyObj : NSObject<NSCopying, NSMutableCopying>
@property (nonatomic, retain) NSMutableString *str1;
@property (nonatomic, retain) NSString *str2;
@property (nonatomic, assign) int num;
@end
MyObj.h

  

//
//  MyObj.m
//  No
//
//  Created by Norcy on 16/1/28.
//  Copyright © 2016年 Norcy. All rights reserved.
//

#import "MyObj.h"

@implementation MyObj
- (id)init
{
    if (self = [super init])
    {
        self.str1 = [[NSMutableString alloc] init];
        self.str2 = [[NSString alloc] init];
        self.num = -1;
    }
    return self;
}

- (id)copyWithZone:(NSZone *)zone
{
    MyObj *obj = [[[self class] allocWithZone:zone] init];
    obj.str1 = [self.str1 copyWithZone:zone];
    obj.str2 = [self.str2 copyWithZone:zone];
//    obj.str1 = [self.str1 copy];  //这样写也能够
//    obj.str2 = [self.str2 copy];
    obj.num = self.num;
    return obj;
}

- (id)mutableCopyWithZone:(NSZone *)zone
{
    MyObj *obj = [[[self class] allocWithZone:zone] init];
    obj.str1 = [self.str1 mutableCopyWithZone:zone];
    obj.str2 = [self.str2 mutableCopyWithZone:zone];
//    obj.str1 = [self.str1 mutableCopy];   //这样写也能够
//    obj.str2 = [self.str2 mutableCopy];
    obj.num = self.num;
    return obj;
}
@end
MyObj.m

 

调用方法以下:

MyObj *obj = [[MyObj alloc] init];
obj.str1 = @"123";
obj.str2 = @"345";
obj.num = 1;
MyObj *obj2 = [obj copy];
MyObj *obj3 = [obj mutableCopy];

 

如上代码,打印结果以下图


能够看到

(1)copy方法准确返回了一个新的对象,且对象的属性是浅复制

(2)mutableCopy方法准确返回了一个新的对象,且对象的属性是深复制

(3)想要实现copy方法,须要让对象声明遵循<NSCopying>和<NSMutableCopying>协议,而且实现实现copyWithZone:和mutableCopyWithZone:方法

 (注意哦,不是实现copy和mutableCopy方法;还有zone参数是什么鬼?其实zone参数的存在是历史缘由,如今咱们没必要太过关心它)

(4)如下这2种写法在该状况下是等价的

    obj.str1 = [self.str1 copyWithZone:zone];
    obj.str2 = [self.str2 copyWithZone:zone];
// obj.str1 = [self.str1 copy]; //这样写也能够 // obj.str2 = [self.str2 copy];

 

参考文章:

《浅谈copy和retain》

相关文章
相关标签/搜索