WWCD 2015: Swift 里的Value Type 和面向协议

本文详细解释了Swift中的valuetype和referencetype的概念、区别及应用场景,包括赋值操作、类型交叉使用等关键点,并讨论了在不同情况下的选择类与valuetype的原因。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

概念

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的问题和解决办法

  1. 隐式共享(implicit sharing): A和B共享一段内存,A改了里面的内容,B出问题了。然后B为了避免这种情况,就自己做了一份copy。copy让系统性能下降。然后,这些代码有可能是在不同线程里面运行的,然后就带来了race condition(不同步),然后B开始加锁。锁让程序变得更慢,还会造成死锁。 解决办法就是Value type。
  2. 类的继承是入侵式的:这个没太看明白,解决办法是delegate
  3. 类会丢失变量属性:比如: 你想要写一个比较所有类型的大小,并排序的类,首先,在你写这个类的时候,你不知道真正排序的类型是什么,也不知道是按照怎样的规则排序。所以会写成这样:
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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值