原文:http://www.jianshu.com/p/5254f1277dba

内存的栈区 : 由编译器自动分配释放, 存放函数的参数值, 局部变量的值等. 其操作方式类似于数据结构中的栈.

内存的堆区 : 一般由程序员分配释放, 若程序员不释放, 程序结束时可能由OS回收. 注意它与数据结构中的堆是两回事, 分配方式倒是类似于链表.


copy方法和mutableCopy方法

如果你想要创建一个对象, 该对象与源对象的内容一致, 那么你可以考虑用拷贝(copy或mutableCopy), 首先, 我将会利用字符串, 数组, 字典这三种常见的对象来说明copy与mutableCopy的区别.

NSString

NSString *string = @"Jerry";
[string copy] --> 拷贝出内容为Jerry的NSString类型的字符串
[string mutableCopy] --> 拷贝出内容为Jerry的NSMutableString类型的字符串

NSDictionary

NSDictionary *dict = @{@"name" : @"Jerry"};
[dict copy] --> 拷贝出内容与dict相同的NSDictionary类型的字典
[dict mutableCopy] --> 拷贝出内容与dict相同的NSMutableDictionary类型的字典

NSArray

NSArray *array = @[@"Jerry"];
[array copy] --> 拷贝出内容与array相同的NSArray类型的数组
[array mutableCopy] --> 拷贝出内容与array相同的NSMutableArray类型的数组

总结

  1. copy拷贝出来的对象类型总是不可变类型(例如, NSString, NSDictionary, NSArray等等)
  2. mutableCopy拷贝出来的对象类型总是可变类型(例如, NSMutableString, NSMutableDictionary, NSMutableArray等等)

深拷贝与浅拷贝

何为深拷贝, 何为浅拷贝?

深拷贝 : 拷贝出来的对象与源对象地址不一致! 这意味着我修改拷贝对象的值对源对象的值没有任何影响.
浅拷贝 : 拷贝出来的对象与源对象地址一致! 这意味着我修改拷贝对象的值会直接影响到源对象.

这里需要纠正网上一些错误的观点(以下为错误观点)

copy都是浅拷贝, mutableCopy都是深拷贝

我们知道, 当我们用copy从一个可变对象拷贝出一个不可变对象时, 这种情况就属于深拷贝而不是浅拷贝!!

注意 ! 深拷贝与浅拷贝也有相对之分!!!看下面

对于NSString对象, 确实深拷贝就是深拷贝, 浅拷贝就是浅拷贝, 没有任何异议.
但是对于NSArray, NSDictionary, NSSet这些容器类的对象呢? 当然浅拷贝依然是指针拷贝, 那深拷贝意味着连同容器及其容器内的对象一并拷贝吗? 还是只拷贝容器对象, 对容器内的对象则只是简单引用呢? 这里有两种情况, 我姑且把它称为不完全深拷贝完全深拷贝

不完全深拷贝

不完全深拷贝就是只拷贝容器对象(拷贝一个壳), 而对于容器内的对象则只保存一份引用.

不完全深拷贝.png

所以我们知道, 就算我们修改copyArray不会影响到源array, 但是我通过copyArray修改数组内的object, 对应地源array内的object也会随之修改, 大家可以自行测试.

完全深拷贝

完全深拷贝就是连同容器内的对象在内, 完完全全拷贝一份出来

完全深拷贝.png

通过图片可以很清楚地知道, 这种情况下无论是修改copyArray还是通过copyArray修改数组内的object, 对源array都不会造成半点影响.

ps : 默认状态下深拷贝指的是不完全深拷贝, 如要实现完全深拷贝, 则要重写copyWithZone: 方法, 自行实现完全深拷贝的需求. 大体思路如下, 在copyWithZone: 里对象赋值上不直接赋值而是通过copy方法即可实现, 这里不作具体讨论.既然有朋友问到, 那就贴上示例代码吧
// Person.m
- (id)copyWithZone:(NSZone *)zone
{
Person *cpyPerson = [[Person allocWithZone:zone] init];
cpyPerson.name = self.name;
cpyPerson.age = self.age;
return cpyPerson;
}
// NSArray
- (id)copy
{
NSArray *cpyArray = [[NSArray alloc] initWithArray:self copyItems:YES];
return cpyArray;
}
// main.m
Person *p1 = [[Person alloc] init];
Person *p2 = [[Person alloc] init];
NSArray *array = @[p1, p2];
NSArray *cpyArray = [array copy];
NSLog(@"%@ - %@", array, cpyArray);
// 输出结果
(
"<Person: 0x100204af0>",
"<Person: 0x100206b20>"
) - (
"<Person: 0x100207910>",
"<Person: 0x1002074d0>"
)

这样就能办到完全深拷贝的目的了.
ps : 官方文档说明copy方法内部默认会调用copyWithZone方法的, 但是NSArray因为未知的原因导致其copy方法不会调用copyWithZone (可能是因为OC中已经废弃了zone这个概念, 苹果官方文档有说), 所以这里我就利用分类重写了NSArray的copy方法, 实际上苹果并不推荐这么做.


block为什么要用copy?

首先, block是一个对象, 所以block理论上是可以retain/release的. 但是block在创建的时候它的内存是默认是分配在栈(stack)上, 而不是堆(heap)上的. 所以它的作用域仅限创建时候的当前上下文(函数, 方法...), 当你在该作用域外调用该block时, 程序就会崩溃.

Apple官方文档

意思就是 : 一般情况下你不需要自行调用copy或者retain一个block. 只有当你需要在block定义域以外的地方使用时才需要copy. Copy将block从内存栈区移到堆区.

其实block使用copy是MRC留下来的也算是一个传统吧, 在MRC下, 如上述, 在方法中的block创建在栈区, 使用copy就能把他放到堆区, 这样在作用域外调用该block程序就不会崩溃. 但在ARC下, 使用copy与strong其实都一样, 因为block的retain就是用copy来实现的, 所以block使用copy还能装装逼, 说明自己是从MRC下走过来的..嘿嘿


copy相对于直接赋值的好处

看看以下代码 :

直接赋值

大家猜猜控制台输出是啥? 是( Kobe ), ( Kobe, McGrady )吗?
错了错了!!!

array = (
Kobe,
McGragy
), mArray = (
Kobe,
McGragy
)

为什么??? 明明可变数组添加对象是在赋值之后, 为什么后面添加对象还会影响到不可变数组呢??
原因很简单, 因为Objective-C支持多态.
所以表面上self.array是NSArray对象, 其实骨子里是NSMutableArray对象.这样的话将会对后期DEBUG增加很大的成本, 可能会导致莫名其妙的错误.
再看以下代码 :

使用copy

大家再来猜一下输出会是什么?
没错!

array = (
Kobe
), mArray = (
Kobe,
McGragy
)

这样就能保证不管赋值的是可变还是不可变数组, NSArray就是NSArray了!(你爸就是你爸, 不可能变成你了)

所以大家现在知道为什么@property中的NSString, NSArray, NSDictionary属性为什么大多时候用copy而不用strong的原因了么?


总结

这里做出了一张图, 帮助新手弄清楚copy与mutableCopy的区别, 大神请无视^_^

copy与mutableCopy

如果能够在你的工程中正确使用copy, 将会对你的程序有不小的帮助.细节决定成败嘛!!

iOS中的copy的更多相关文章

  1. 小结 iOS 中的 copy

    预备知识 : 内存的栈区 : 由编译器自动分配释放, 存放函数的参数值, 局部变量的值等. 其 操作方式类似于数据结构中的栈. 内存的堆区 : 一般由程序员分配释放, 若程序员不释放, 程序结束时可能 ...

  2. iOS中assign、copy 、retain等关键字的含义

    iOS中assign.copy .retain等关键字的含义  转自:http://my.oschina.net/majiage/blog/267409 assign: 简单赋值,不更改索引计数cop ...

  3. iOS中copy和strong修饰符的区别

    iOS中copy和strong修饰符的区别 //用copys修饰的生成的都是不可变的对象 ,如果调用可变类型方法的直接报错 @property(nonatomic,copy)NSString * cp ...

  4. iOS中的数据持久化方式

    iOS中的数据持久化方式,基本上有以下四种:属性列表.对象归档.SQLite3和Core Data. 1.属性列表 涉及到的主要类:NSUserDefaults,一般 [NSUserDefaults ...

  5. iOS:iOS中的多控制器管理

    iOS中的控制器有三种创建方式: 1.通过storyboard创建 UIStoryboard *storyboard = [UIStoryboard storyboardWithName:@" ...

  6. IOS中的Block与C++11中的lambda

    ios中的block 可以说是一种函数指针,但更确切的讲,其实际上其应该算是object-c对C++11中lambda的支持或者说是一个语言上的变体,其实际内容是一样的,C++的lambda我已经有简 ...

  7. iOS中几种常用的数据存储方式

    自己稍微总结了一下下,方便大家查看 1.write直接写入文件的方法 永久保存在磁盘中,可以存储的对象有NSString.NSArray.NSDictionary.NSData.NSNumber,数据 ...

  8. iOS中的存储方式

    1.Plist 1.1 了解沙盒 每个iOS应用都有自己的应用沙盒(应用沙盒就是文件系统目录),与其它文件系统隔离.应用必须呆在自己的沙盒里.其它应用不能访问该沙盒. 一个程序中所有的非代码文件都可以 ...

  9. iOS中JSONModel的使用

    iOS中JSONModel的使用   流弊的JSON数据模型框架 https://github.com/jsonmodel/jsonmodel 版本 1.3.0 如果你喜欢JSONModel,并且使用 ...

随机推荐

  1. maven多module项目中千万不要引入其它模块的单元測试代码

    本文出处:http://blog.csdn.net/chaijunkun/article/details/35796335,转载请注明. 因为本人不定期会整理相关博文,会对对应内容作出完好. 因此强烈 ...

  2. css 下边框

    float: left; width: 1200px; height: 42px; background-color: #fff0; /* background-color: #4f4aff; */ ...

  3. Python 各种测试框架简介(三):nose

    转载:https://blog.csdn.net/qq_15013233/article/details/52527260 摘要 这里将从(pythontesting.net)陆续编译四篇 Pytho ...

  4. 隐藏执行批处理bat文件

    当kali成功溢出目标以后, 如果我们需要目标主机执行批处理bat的话, 目标机器会出现黑色的弹窗, 用户看到一个黑色弹窗肯定会奇怪, 以下有两种方法让bat文件运行起来: 1:使用bat转化为exe ...

  5. 构造并发送Beacon帧以伪造任意WiFi热点

    请想象一下这样的情景:你可以任意伪造很多个WiFi热点, 这个技术只能在linux上使用,而且对无线网卡也有一定的挑剔,具体的下面会讲- 阶段一:基本原理 首先需要搞清楚的是,手机.电脑等支持WiFi ...

  6. Mina.Net实现的UDP协议消息收发Demo

    using Mina.Filter.Codec; using Mina.Filter.Codec.TextLine; using System; using System.Collections.Ge ...

  7. Android学习笔记十:异步处理

    转载请注明原文地址:http://www.cnblogs.com/ygj0930/p/7520700.html 一:基础概念 UI线程:当Android程序第一次启动时,Android会同时启动一条主 ...

  8. Python定向爬虫实战

    转载请注明原文地址:http://www.cnblogs.com/ygj0930/p/7019963.html 一:requests模块介绍 requests是第三方http库,可以十分方便地实现py ...

  9. 仿饿了么增加购物车旋转控件 - 自带闪转腾挪动画 的button

    本篇文章已授权微信公众号 guolin_blog (郭霖)独家公布 转载请标明出处: http://blog.csdn.net/zxt0601/article/details/54235736 本文出 ...

  10. 测试json字符和java对象属性不一样在多个json框架下转换的表现

    package com.longge.mytest; import java.io.IOException; import org.junit.Test; import com.alibaba.fas ...