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

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

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

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

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

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

结论:

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

2.str3在编译时为NSString,运行时为NSMutableString类型,从图中str3的类型为__NSCFString可证明,所以修改操作在编译的时候就会报错

3.str4在编译时为NSMutableString,运行时为NSString类型,从图中str4的类型为__NSCFConstantString可证明。所以对str4进行append等修改,编译可通过,但运行时会直接crash

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

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

结论:

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

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

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

NSArray *array1 = [NSArray arrayWithObjects:[NSMutableString stringWithString:@""], @"", 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 = -;
}
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 = @"";
obj.str2 = @"";
obj.num = ;
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》

浅析Objective-C的copy的更多相关文章

  1. objective c,copy, mutableCopy区别

    copy总是返回不能被修改的对象,mutableCopy返回可以被修改的对象 例: NSArray *array = @[@"test", @"test2"]; ...

  2. Objective C assign&copy & retain区别

    什么是assign,copy,retain之间的区别? assign: 简单赋值,不更改索引计数(Reference Counting). copy: 建立一个索引计数为1的对象,然后释放旧对象 re ...

  3. objective c, property, copy

    @property (copy) nsmutablearray *array -copy, as implemented by mutable Cocoa classes, always return ...

  4. Automake

    Automake是用来根据Makefile.am生成Makefile.in的工具 标准Makefile目标 'make all' Build programs, libraries, document ...

  5. HEC-ResSim原文档

              HEC-ResSim Reservoir System Simulation             User's Manual       Version 3.1 May 201 ...

  6. Objective -C学习笔记 之copy(复制)

    //自定义类对象实现copy需要遵守copy协议(否则程序崩溃),实现必须实现的协议方法,里面的代码就决定了你的copy是深是浅 #import <Foundation/Foundation.h ...

  7. Flex对象的Clone & Copy浅析

    在flex中有时候会用到ObjectUtil.clone和ObjectUtil.copy方法.下面是官方API的注释. 克隆指定对象,并返回对该克隆的引用.该克隆使用本机序列化技术生成.这意味着在克隆 ...

  8. python 浅析格式化输出和深浅copy

    一,格式化输出 今天主要想记录一下关于格式化输出的例子,然后结合了自己的理解,分析如下: 格式是 :百分号+占位符 主要有三种使用形式:%s  (其中s表示string)表示字符串 %d  (其中d表 ...

  9. python浅析格式化输出和深浅copy

    一,格式化输出 今天主要想记录一下关于格式化输出的例子,然后结合了自己的理解,分析如下: 格式是 :百分号+占位符 主要有三种使用形式:%s  (其中s表示string)表示字符串 %d  (其中d表 ...

随机推荐

  1. paip.提升用户体验--radio图片选择器 easyui 实现..

    #paip.提升用户体验--radio图片选择器 easyui 实现.. =================================== ##原因... ------------------- ...

  2. Paip.声明式编程以及DSL 总结

    Paip.声明式编程以及DSL 总结     1.1      声明式编程DSL 1.2      声明式语言) 1.3      声明式编程框架AOP实现 1.4      应用场合 1.5     ...

  3. paip. uapi 过滤器的java php python 实现aop filter

    paip. uapi 过滤器的java php python 实现aop filter filter 是面向切面编程AOP.. 作者Attilax  艾龙,  EMAIL:1466519819@qq. ...

  4. Java集合——题目

    第一题 (Map)利用Map,完成下面的功能: 从命令行读入一个字符串,表示一个年份,输出该年的世界杯冠军是哪支球队.如果该 年没有举办世界杯,则输出:没有举办世界杯. 附:世界杯冠军以及对应的夺冠年 ...

  5. [转]Oracle因安装时未设定字符集导致中文乱码的解决方案

    在CentOS 6.4上安装Oracle 11g没有设定字符集,采用的是操作系统默认字符集:WE8MSWIN1252,将字符集修改为:AL32UTF8. SQL> select userenv( ...

  6. HTML、XHTML XML和DHTML的区别

    XML与HTML的设计区别是:XML是用来存储数据的,重在数据本身.而HTML是用来定义数据的,重在数据的显示模式 XHTML(The Extensible HyperText Markup Lang ...

  7. 使用Reveal查看任意App的技巧

    转:http://www.jianshu.com/p/4dc8f94ca27c 前言 Reveal(http://revealapp.com)是一个很强大的iOS View Hierarchy工具,与 ...

  8. 解决中64位Win7系统上PLSQL无法连接ORACLE的方法(PLSQL无法识别ORACLE_HOME的配置)

    最近新安装了64位的Win7系统,工作中需要用oracle数据库,而数据库是公司IT的DBA进行管理和维护的. 我们只需要连接上去进行使用就可以了,于是我就在自己的机器上安装了oracle clien ...

  9. ARM Cortex Debug Port Access Port DP AP JTAG-DP SW-DP SWJ-DP JTAG-AP MEM-AP

  10. Java 7 jps - JVM Process Status Tool

    本文内容 语法 参数 描述 选项 主机标识符 输出格式 示例 参考资料 先发出来,然后慢慢翻译~ 语法 jps [ options ] [ hostid ] 参数 options 命令行参数. hos ...