浅析Objective-C的copy
一直对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];
参考文章:
浅析Objective-C的copy的更多相关文章
- objective c,copy, mutableCopy区别
copy总是返回不能被修改的对象,mutableCopy返回可以被修改的对象 例: NSArray *array = @[@"test", @"test2"]; ...
- Objective C assign© & retain区别
什么是assign,copy,retain之间的区别? assign: 简单赋值,不更改索引计数(Reference Counting). copy: 建立一个索引计数为1的对象,然后释放旧对象 re ...
- objective c, property, copy
@property (copy) nsmutablearray *array -copy, as implemented by mutable Cocoa classes, always return ...
- Automake
Automake是用来根据Makefile.am生成Makefile.in的工具 标准Makefile目标 'make all' Build programs, libraries, document ...
- HEC-ResSim原文档
HEC-ResSim Reservoir System Simulation User's Manual Version 3.1 May 201 ...
- Objective -C学习笔记 之copy(复制)
//自定义类对象实现copy需要遵守copy协议(否则程序崩溃),实现必须实现的协议方法,里面的代码就决定了你的copy是深是浅 #import <Foundation/Foundation.h ...
- Flex对象的Clone & Copy浅析
在flex中有时候会用到ObjectUtil.clone和ObjectUtil.copy方法.下面是官方API的注释. 克隆指定对象,并返回对该克隆的引用.该克隆使用本机序列化技术生成.这意味着在克隆 ...
- python 浅析格式化输出和深浅copy
一,格式化输出 今天主要想记录一下关于格式化输出的例子,然后结合了自己的理解,分析如下: 格式是 :百分号+占位符 主要有三种使用形式:%s (其中s表示string)表示字符串 %d (其中d表 ...
- python浅析格式化输出和深浅copy
一,格式化输出 今天主要想记录一下关于格式化输出的例子,然后结合了自己的理解,分析如下: 格式是 :百分号+占位符 主要有三种使用形式:%s (其中s表示string)表示字符串 %d (其中d表 ...
随机推荐
- android 给空白包签名
前言:之前公司app在腾讯开放平台认领应用时,涉及了一个问题:就是给空白包签名.然后再上传上去审核. 腾讯开放平台的官方说明如下, 如何签名:jarsgner-verbose-keystore[key ...
- 3D touch 静态、动态设置及进入APP的跳转方式
申明Quick Action有两种方式:静态和动态 静态是在info.plist文件中申明,动态则是在代码中注册,系统支持两者同时存在. -系统限制每个app最多显示4个快捷图标,包括静态和动态 静态 ...
- 今日例子border
border这个属性在页面上的使用率还是很高,例如我们需要理解的盒模型就需要对border有个 比较深的理解,如果你会盒模型,但对border没有深的理解,那只能说你只是知道盒模型,而 不是懂得盒模型 ...
- 如何设置缺省路由 route hosts(仅助记) 马连洼 马连洼 马连洼
linux下添加路由的方法:一:使用 route 命令添加使用route 命令添加的路由,机器重启或者网卡重启后路由就失效了,方法://添加到主机的路由# route add –host 192.16 ...
- Android之判断当前指定App是否在前台
直接上代码,不多说 //在进程中去寻找当前APP的信息,判断是否在前台运行 private boolean isAppOnForeground() { ActivityManager activity ...
- [轉載]史上最强php生成pdf文件,html转pdf文件方法
之前有个客户需要把一些html页面生成pdf文件,然后我就找一些用php把html页面围成pdf文件的类.方法是可谓是找了很多很多,什么html2pdf,pdflib,FPDF这些都试过了,但是都没有 ...
- Codeforces Beta Round #80 (Div. 2 Only)【ABCD】
Codeforces Beta Round #80 (Div. 2 Only) A Blackjack1 题意 一共52张扑克,A代表1或者11,2-10表示自己的数字,其他都表示10 现在你已经有一 ...
- ubuntu 休眠之后网络间接失败 can not connect to network after suspend (wake up)
ubuntu for laptop系统在系统休眠后wakeup 之后,网络连接失败, 有线网络无法连接, 无线wifi无法连接, 只能重启后才能恢复, 此时可以采用以下方法处理: 1. 在/etc/p ...
- HL AsySocket 服务开发框架 - 一般性测试1
一 概述 Socket服务器性能要好就要经过无数次的测试,来保证,以下是记录一次的测试经过. 机器配置:Inter(R) Core(TM) i3-2310m CPU 2.10GHz RAM 6.00G ...
- Ecshop文章列表页显示内容摘要
本教程中讲到的“内容摘要”指的是文章内容的前 60个字符(当然也可以是前40个,前50个等等) 下面以 2.7.2版 + 官方默认模板 为例进行讲解: 1).修改 includes/lib_artic ...