属性观察_Swift

属性观察 (Property Observers) 是 Swift 中一个很特殊的特性,利用属性观察我们可以在当前类型内监视对于属性的设定,并作出一些响应。Swift 中为我们提供了两个属性观察的方法,它们分别是willSetdidSet

使用这两个方法十分简单,我们只要在属性声明的时候添加相应的代码块,就可以对将要设定的值和已经设置的值进行监听了:

class MyClass {
    var date: NSDate {
        willSet {
            println("即将将日期从 \(date) 设定至 \(newValue)")
        }

        didSet {
            "已经将日期从 \(oldValue) 设定至 \(date)")
        }
    }

    init() {
        date = NSDate()
    }
}

let foo = MyClass()
foo.date = foo.date.dateByAddingTimeInterval(10086)

// 输出
// 即将将日期从 2014-08-23 12:47:36 +0000 设定至 2014-08-23 15:35:42 +0000
// 已经将日期从 2014-08-23 12:47:36 +0000 设定至 2014-08-23 15:35:42 +0000

didSet中我们分别可以使用newValueoldValue获取将要设定的和已经设定的值。属性观察的一个重要用处是作为设置值的验证,比如上面的例子中我们不希望date超过当前时间的一年以上的话,我们可以将didSet修改一下:

let oneYearInSecond: NSTimeInterval = 365 * 24 * 60 * 60
    var date: NSDate {

        //...

        didSet {
            if (date.timeIntervalSinceNow > oneYearInSecond) {
                "设定的时间太晚了!")
                date = NSDate().dateByAddingTimeInterval(oneYearInSecond)
            }
            "已经将日期从 \(oldValue) 设定至 \(date)")
        }
    }

    //...
}

更改一下调用,我们就能看到效果

// 365 * 24 * 60 * 60 = 31_536_000
foo.date = foo.date.dateByAddingTimeInterval(100_000_000)

// 即将将日期从 2014-08-23 13:24:14 +0000 设定至 2017-10-23 23:10:54 +0000
// 设定的时间太晚了!
// 已经将日期从 2014-08-23 13:24:14 +0000 设定至 2015-08-23 13:24:14 +0000

A>初始化方法属性的设定,以及在didSet
A>对属性的再次设定都不会再次触发属性观察的调用,放心吧。

我们知道,在 Swift 中所声明的属性包括存储属性和计算属性两种。其中存储属性将会在内存中实际分配地址对属性进行存储,而计算属性则不包括背后的存储,只是提供setget两种方法。在同一个类型中,属性观察和计算属性是不能同时共存的。也就是说,想在一个属性定义中同时出现willSetdidSet是一件办不到的事情。计算属性中我们可以通过改写set中的内容来达到和willSetdidSet同样的属性观察的目的。如果我们无法改动这个类,又想要通过属性观察做一些事情的话,可能就需要子类化这个类,并且重写它的属性了。重写的属性并不知道父类属性的具体实现情况,而只从父类属性中继承名字和类型,因此在子类的重载属性中我们是可以对父类属性任意地添加属性观察的,而不用在意父类中到底是存储属性还是计算属性

A {
    var number :Int {
        get {
            "get")
            return 1
        }

        set {"set")}
    }
}

B: override var number: Int {
        willSet {"willSet")}
        didSet {"didSet")}
    }
}

调用numberset方法可以看到工作的顺序

let b = B()
b.number = 0

// get
// willSet
// set
// didSet

set和对应的属性观察的调用都在我们的预想之中。这里要注意的是get首先被调用了一次。这是因为我们实现了didSetdidSet中会用到oldValue,而这个值需要在整个set动作之前进行获取并存储待用,否则将无法确保正确性。如果我们不实现didSet的话,这次get操作也将不存在。

相关文章

软件简介:蓝湖辅助工具,减少移动端开发中控件属性的复制和粘...
现实生活中,我们听到的声音都是时间连续的,我们称为这种信...
前言最近在B站上看到一个漂亮的仙女姐姐跳舞视频,循环看了亿...
【Android App】实战项目之仿抖音的短视频分享App(附源码和...
前言这一篇博客应该是我花时间最多的一次了,从2022年1月底至...
因为我既对接过session、cookie,也对接过JWT,今年因为工作...