一直对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. python函数的参数

    代码: # coding=utf8 # 可以传入任何个参数 def calc(*numbers): sum = 0 for n in numbers: sum = sum + n * n return ...

  2. 前端与Server端(路由)

    路由(前端):原理:只有几个XHR请求,就能实现页面无刷新闪烁更改URL 前端:1. ajax承担数据通信以及相对应的逻辑(交互逻辑) ajax进行数据交互,跟URL打交道,让数据交互的变化反映到UR ...

  3. AndroidManifest常见的设置解析

    AndroidManifest.xml清单文件是每个Android项目所必需的,它是整个Android项目的全局描述文件.AndroidManifest.xml清单文件说明了该应用的名称.所使用的图标 ...

  4. Apache Solr查询语法(转)

    查询参数 常用: q - 查询字符串,必须的. fl - 指定返回那些字段内容,用逗号或空格分隔多个. start - 返回第一条记录在完整找到结果中的偏移位置,0开始,一般分页用. rows - 指 ...

  5. Solr5之Schema.xml详解

    schema.xml 是用来定义索引数据中的域的,包括域名称,域类型,域是否索引,是否分词,是否存储,是否标准化即 Norms ,是否存储项向量等等. schema.xml 配置文件的根元素就是 sc ...

  6. 2016年 最火的 15 款 HTML5 游戏引擎

    HTML5游戏从2014年Egret引擎开发的神经猫引爆朋友圈之后,就开始一发不可收拾,今年<传奇世界>更是突破流水2000万!从两年多的发展来看,游戏开发变得越来越复杂,需要制作各种炫丽 ...

  7. Win C盘扩容

    最近C盘真的空间越来越小了,记下简单的几个操作步骤以便以后用到. 参考文档: http://jingyan.baidu.com/article/90808022a6c6b7fd91c80fc8.htm ...

  8. 轻松搞定面试中的二叉树题目(java&python)

    树是一种比较重要的数据结构,尤其是二叉树.二叉树是一种特殊的树,在二叉树中每个节点最多有两个子节点,一般称为左子节点和右子节点(或左孩子和右孩子),并且二叉树的子树有左右之分,其次序不能任意颠倒.二叉 ...

  9. mysql设置连接超时时间参数:wait_timeout

    [root@ ~]# mysql -h 192.168.0.* -uroot -pEnter password: Welcome to the MySQL monitor. Commands end ...

  10. Updating Protobuf and GRPC in Golang

    转自: http://russmatney.com/techsposure/update-protobuf-golang-grpc/ TL;DR: When protobuf updates, all ...