概念
apple把swift里面的类型分为两种: value type和reference type。
所有Swift里面的基础类型,collection类型,包含value type的类型都是value type:
- 基础类型:Int, Double, String
- collection类型: Array, Set, Dictionary
- 包含value type的类型:tuples,structs,和enums(枚举)
value type和reference type的区别:
value type的例子:
var i = 1
var j = i
j = 4
println("i = \(i), j = \(j)")
输出: "i = 1, j = 4"
或者,用struct 举例
struct SomeStruct {
var number: Int = 0
}
var value = SomeStruct()
value.number = 42
var value2 = value
value.number = 43
print("The number in value2 is \(value2.number)")
输出:The number in value2 is 42
reference type
class SomeClass {
var number: Int = 0
}
var reference = SomeClass()
reference.number = 42
var reference2 = reference
reference.number = 43
print("The number in reference2 is \(reference2.number)")
输出:The number in reference2 is 43
其实我们已经熟悉value type,int类型就是典型的value type。在所有的语言里面。只是,swift把许多属于reference type的作为的value type, 比如: struct。看一个struct在OC里面的例子:
@interface SomeClass : NSObject
@property int number;
@end
@implementation SomeClass
@end
struct SomeStruct {
int number;
};
SomeClass *reference = [[SomeClass alloc] init];
reference.number = 42;
SomeClass *reference2 = reference;
reference.number = 43;
NSLog(@"The number in reference2 is %d", reference2.number);
输出
The number in reference2 is 43
可以看出两种类型的不同就在于,value type在“=”的时候,做了一次copy。而reference type没有。
两种type交叉使用
- 一个value type 包含一个value type:当赋值的时候,都会做拷贝
- 一个reference type 包含一个value type:当赋值的时候,都不会做拷贝。
class referenceOuter {
var valueInter: Int = 0
}
var outer1 = referenceOuter()
outer1.valueInter = 1
var outer2 = outer1
outer2.valueInter = 2
println("\(outer1.valueInter)") // 输出 2
- 一个reference type 包含一个reference type:当赋值的时候,都不会做拷贝。
- 一个value type 包含一个reference type:当赋值的时候, value type 会做拷贝,但是reference type不会,比如: 一个struct包含一个nssting, 赋值过后nssting还是指向原来的地址:
struct valueOuter {
var referenceInter: NSString = ""
}
var outer1 = valueOuter()
outer1.referenceInter = "this is outer1"
var outer2 = outer1
println("\( unsafeAddressOf(outer1.referenceInter)) \(unsafeAddressOf(outer2.referenceInter))")
什么时候用类:
- 当你真的想要用隐式共享的时候,隐式共享就是指一块内存,有2个及其以上的指针指向它。面向对象里,很多都是这种情况。什么时候真想用隐式共享呢:
- 你想不出来copy和比较有什么意义的时候。比如:window,一个app只需要一个window,不需要copy,如果弄2个window是什么意思?
- 变量会联系到外部设备,比如:磁盘上的文件。
- 变量只是一个sink(接受端),只写,不能读。比如:Render(图像渲染器),你叫render画一条线。
- 要继承系统的框架的时候。
说白了,就只有你要写的MVC中的M,可能是完全用协议的,其他都不得不继承于一个类,谈到继承,就一定是一个class。
OOP的问题和解决办法
- 隐式共享(implicit sharing): A和B共享一段内存,A改了里面的内容,B出问题了。然后B为了避免这种情况,就自己做了一份copy。copy让系统性能下降。然后,这些代码有可能是在不同线程里面运行的,然后就带来了race condition(不同步),然后B开始加锁。锁让程序变得更慢,还会造成死锁。 解决办法就是Value type。
- 类的继承是入侵式的:这个没太看明白,解决办法是delegate
- 类会丢失变量属性:比如: 你想要写一个比较所有类型的大小,并排序的类,首先,在你写这个类的时候,你不知道真正排序的类型是什么,也不知道是按照怎样的规则排序。所以会写成这样:
class Ordered {
func procedes(other: Ordered)->Bool {fatalError("implement me")}
}
func binarySearch(sortedKeys: [Ordered], forKey k:Ordered) -> Int {
var lo = 0, hi = sortedKeys.count
while hi > lo {
let mid = lo + (hi - lo) / 2
if sortedKeys[mid].procedes(k) {lo = mid + 1}
else {hi = mid}
}
return lo
}
class Number: Ordered {
var value: Double = 0
override func procedes(other: Ordered)-> Bool {
return value < (other as! Number).value
}
}
上面的代码有2个地方有问题,一个是调用了fatalError,一个是用了as!,丢失了属性。 用protocal可以解决这2个问题。
protocal
t.b.d
参考:
When to Use Swift Structs and Classes
Protocol-Oriented Programming in Swift
Building Better Apps with Value Types in Swift