寒哥带你深入了解下Swift中的Value Type
http://www.cocoachina.com/swift/20150923/13539.html
关于开发到底使用ValueType 值类型还是Reference Type 引用类型,关于这个,Swift:什么时候使用结构体和类这个文章写得比较好 这里我就不再多说了 我只带大家深入了解一下。
大家都知道值类型在赋值的时候做的是值复制的过程,引用类型赋值做的是引用复制,但实例不复制。
但是有没有想过嵌套类型呢?比如以下4种(只讨论一层嵌套最后会做总结)
引用类型嵌套引用类型
值类型嵌套值类型
引用类型嵌套值类型
值类型嵌套引用类型
引用类型嵌套引用类型
代码如下
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
class Inner { var value = 99 } class Outter { var value = 99 var inner = Inner() } var out1 = Outter() var out2 = out1 out1.value = 100 out1.inner.value = 100 print( "outer2.value=\(out2.value) outer2.inner.value=\(out2.inner.value)" ) |
结果为
"outer2.value=100 outer2.inner.value=100\n"
画图分析
Paste_Image.png
结论:
如果你有一个引用类型嵌套了另外一个引用类型,没有什么特别的事会发生。像通常那样,任何一个指向内部或者外部值的指针都能操纵他指向的对象。只要其中一个引用操纵值使其改变,其他引用指向的值也就跟着变了。
值类型嵌套值类型
1
2
3
4
5
6
7
8
|
struct Inner { var value = 99 } struct Outter { var inner = Inner() var value = 99 } |
情况1 只复制外部值
1
2
3
4
5
6
|
var out1 = Outter() var out2 = out1 out1.value = 100 out1.inner.value = 100 print( "outer2.value=\(out2.value) outer2.inner.value=\(out2.inner.value)" ) |
结果:
"outer2.value=99 outer2.inner.value=99\n"
画图分析
Paste_Image.png
2 只复制内部值
1
2
3
4
5
|
var out3 = Outter() var innter = out3.inner innter.value = 100 out3.value //99 out3.inner.value //99 |
画图
Paste_Image.png
结论
2 如果你有一个值类型嵌套了另外一个值类型,这就会有效地使值所占的内存区域变大。内部值是外部值的一部分。如果你把外部值放到一块新的存储空间里,所有的值包括内部值都会被拷贝。如果你把内部值放进一块新的存储空间中,只有内部值会被拷贝。
引用类型嵌套值类型
1
2
3
4
5
6
7
8
9
10
11
12
13
|
struct Inner { var value = 99 } class Outter { var inner = Inner() var value = 99 } var out1 = Outter() var out2 = out1 out1.value = 100 out1.inner.value = 100 print( "outer2.value=\(out2.value) outer2.inner.value=\(out2.inner.value)" ) |
结果
"outer2.value=100 outer2.inner.value=100\n"
画图分析
Paste_Image.png
结论
3 一个引用类型嵌套了一个值类型会有效扩大这个引用类型所占内存区域。任何指向外部值的指针都可以操纵一切,包括嵌套的内部值。内部值的任何改变对于引用外部值的指针来说都是可见的。如果你把内部值放进一块新的存储区,就会在那块存储区拷贝一份新的值。
以上是三种常见情况
下面是最重要的
下面是最重要的
下面是最重要的
值类型嵌套引用类型
1
2
3
4
5
6
7
8
9
10
11
12
13
|
class Inner{ var value = 99 } struct Outter { var inner = Inner() var value = 99 } var out1 = Outter() var out2 = out1 out1.value = 100 out1.inner.value = 100 print( "outer2.value=\(out2.value) outer2.inner.value=\(out2.inner.value)" ) |
结果
"outer2.value=99 outer2.inner.value=100\n"
画图分析
Paste_Image.png
结论
一个值类型嵌套一个引用类型就没有那么简单了。你可以有效地打破值语义而不被察觉。这可能是好的也可能是坏的,取决于你怎么做。当你把一个引用类型嵌套进一个值类型中,外部值被放进一块新的内存区域时就会被拷贝,但是拷贝的对象仍然指向原始的那个嵌套对象。
对上面的举例
尽管outer2获取了value的一份拷贝,它只拷贝了inner的引用,因此两个结构体就共用了同一个inner对象。这样一来当改变outer.inner.value的值也会影响outer2.inner.value的值。哎呀!
这个行为会很有用。当你小心使用,你创建的结构体就具有写时拷贝功能(只有当你执行outer2.value = 43时才会真正的产生一个副本,否则outer2与outer仍指向共同的资源),这种高效的值语义的实现不会使数据拷贝得到处都是。Swift 中的集合就是这么做的,你也可以自己创建一个这样的类型。想要了解更多请看Let’s Build Swift.Array.
无论在什么时候你移动一个值类型他都会被拷贝,而引用类型则是产生了对同样的底层对象的一个新的引用。那也就意味着引用类型的改变对所有其他的引用都是可见的,而改变值类型只影响你改变的那块内存区域。当选择使用哪种类型时,考虑你的类型是否适合被拷贝,当类型从本质上来说是可拷贝时倾向使用值类型。最后,记住如果你在值类型中嵌入引用类型,不小心的话就会出错!
~~ByeBye
等等 你给我讲了这么多 貌似没什么用啊
错 用出躲到你都遗忘了
在我们Swift 的世界中 String Array Dictionary 都是ValueType,那么在他们装了一个AnyObject 的是不是一个Value Type Contain a ReferenceType
下面我们拿Array 距离 Array 可以看做一个特殊的Dictionary 表现形式其实是一样的。
Paste_Image.png
例子
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
class Person { var value = 99 } let p1 = Person() let p2 = Person() let p3 = Person() let p4 = Person() let p5 = Person() var array1:Array= [p1,p2,p3,p4,p5] var array2 = array1 array2.removeLast() array2.first!.value = 100 print(array1.first!.value) |
画图分析
Paste_Image.png
虽然数组是值类型 在复制的时候会重新生成一个结构体的实例
但是数组内部指向的元素还是同一个
到这里很多人或许还觉得讲的没用
那我们拿OC举例子
1
|
@property(nonatomic,copy) NSString * verifyCode; |
很多人都会这么写 但是不知道为什么 原因就是我们要保证对象的不变性 防止别人修改我自己的东西 那如果NSString 是ValueType 不就解决了 Swift中的String 是这样做的
再来
1
2
3
4
5
|
@property (nonatomic, copy)NSDictionary *dataDic; - (void)setDataDic:(NSDictionary *)dataDic { _dataDic = [dataDic copy]; } |
很多人没这样用过 但是对NSDictionary也copy 是为什么 也是为了 自己存的数据不能被别人修改 那么Swift Dictionary 也是这样设计的
对于Array也是这样设计的
如果你真的需要Reference Type 的Swift 在Foundation的库里面也有对应的实现 NSString NSDictionary NSArray
最后建议 多多用ValueType 编程吧
文中的源代码和keynote 已上传到Github
寒哥带你深入了解下Swift中的Value Type的更多相关文章
- 【凯子哥带你学Framework】Activity界面显示全解析(下)
咱们接着上篇继续讲,上篇没看的请戳:[凯子哥带你学Framework]Activity界面显示全解析(上) 如何验证上一个问题 首先,说明一下运行条件: //主题 name="AppThem ...
- 寒哥细谈之AutoLayout全解
文/南栀倾寒(简书作者)原文链接:http://www.jianshu.com/p/683fbcbfb705著作权归作者所有,转载请联系作者获得授权,并标注“简书作者”. 看到群中好多朋友还停留在Fr ...
- 【凯子哥带你学Framework】Activity启动过程全解析
It’s right time to learn Android’s Framework ! 前言 学习目标 写作方式 主要对象功能介绍 主要流程介绍 zygote是什么有什么作用 SystemSer ...
- 寒哥教你学 iOS - 经验漫谈(转)
转自http://www.cocoachina.com/ios/20150907/13339.html 本篇文章主要讲解 4个问题 load妙用 aop面向切面编程 NSNumber Or Int @ ...
- 【转载】【凯子哥带你学Framework】Activity启动过程全解析
It's right time to learn Android's Framework ! 前言 一个App是怎么启动起来的? App的程序入口到底是哪里? Launcher到底是什么神奇的东西? ...
- 在Swift中应用Grand Central Dispatch(下)
在第一部分中, 你学到了并发,线程以及GCD的工作原理.通过使用dispatch_barrrier和dispatch_sync,你做到了让 PhotoManager单例在读写照片时是线程安全的.除此之 ...
- 基于jQuery带图标的多级下拉菜单
之前为大家分享了很多导航菜单.今天我们要来分享一款很不错的jQuery左侧带小图标的多级下拉菜单,菜单是垂直的,每一个菜单项带有一个小图标,看起来非常专业.并且菜单支持无限极下拉,所以对各位Web开发 ...
- SQL Server 2014新特性:五个关键点带你了解Excel下的Data Explorer
SQL Server 2014新特性:五个关键点带你了解Excel下的Data Explorer Data Explorer是即将发布的SQL Server 2014里的一个新特性,借助这个特性讲使企 ...
- 寒哥教你学iOS - 经验漫谈
http://www.jianshu.com/p/cb54054d3add 寒哥教你学iOS - 经验漫谈 字数2848 阅读1896 评论19 喜欢43 顺便来个广告 iOS开发者 群1734993 ...
随机推荐
- 如何用SPSS做联合分析
如何用SPSS做联合分析 如果产品的描述是由几个属性特征决定的,比如说mp3的音质.外形.容量.价格等等,商家为了确定哪个属性对消费者的影响最大,以及预测什么样的属性组合最受消费者的欢迎,选择的办法应 ...
- JS控制视频的播放
在用js定时器控制视频时, html部分: <video id="video_1"> <source id="source_1" src=&q ...
- 【One by one系列】一步步部署.net core应用
我们的目标: CentOS系统 nginx服务器 asp.net core应用 mysql服务器 腾讯云服务器 工具准备 [Xshell]--使用windwos下的工具Xshell,原理就是使用SHH ...
- 轻松搞定 JS 的this、call和apply
年前最后一篇文章,提前祝大家春节快乐.对了,还有369就要2018年了,提前祝大家2018年春节快乐. .. .vr qBMBBBMBMY 8BBBBBOBMBMv iMBMM5vOY:BMBBv . ...
- 洛谷 P3956 棋盘
题目描述 有一个m ×m的棋盘,棋盘上每一个格子可能是红色.黄色或没有任何颜色的.你现在要从棋盘的最左上角走到棋盘的最右下角. 任何一个时刻,你所站在的位置必须是有颜色的(不能是无色的), 你只能向上 ...
- SOFARPC学习(一)
接触SOFARPC,是从一个好朋友(女程序媛)的推荐开始,目的是从头到尾了解这个框架,包括使用方法和源码解析. 当学习一个新东西的事物,我总喜欢先总体把握,在深入细节,这样就可以有种高屋建瓴的感觉,否 ...
- 闲聊CSS之关于clearfix--清除浮动
一,什么是.clearfix 你只要到Google或者Baidu随便一搜"css清除浮动",就会发现很多网站都讲到"盒子清除内部浮动时可以用到.clearfix" ...
- JSP内置对象解析
out对象:(PrintWriter类的实例) 用来向客户端输出信息,除了输出各种信息外还负责对缓冲区进行管理: 主要方法: print / println void 输出数据 newLine() v ...
- os模块和sys模块
1.os模块与path有关:os.path.isfile():判断置顶对象是否为文件,是返回True,否返回Falseos.path.isdir():判断指定对象是否为目录,是返回True,否返回Fa ...
- oracle习题-简单查询
题一 1 实现将已知表中的数据插入到另一个表中 学生表:stu1 向表中插入两条数据 学生信息表2:stuinfo 将stu1表中的两条数据导入到stuinfo表中,执行下列语句 此时查看一下st ...