首页 » iOS编程基础:Swift、Xcode和Cocoa入门指南 » iOS编程基础:Swift、Xcode和Cocoa入门指南全文在线阅读

《iOS编程基础:Swift、Xcode和Cocoa入门指南》3.4 计算变量

关灯直达底部

到目前为止,本章所介绍的变量都是存储下来的变量,就像盒子一样。变量是个名字,就像盒子一样;值可以通过赋给变量放到盒子中,然后等待通过引用该变量进行获取,只要变量存在就行。

此外,变量还可以计算出来。这意味着变量不再持有值,而是持有函数。在给变量赋值时,函数setter会被调用。当引用变量时,另一个函数getter会被调用。如下代码演示了声明计算变量的语法:


var now : String { ①    get { ②        return NSDate.description ③    }    set { ④        print(newValue) ⑤    }}  

①变量必须是个var(不能是let)。其类型必须要显式声明,后跟一对花括号。

②getter函数叫作get。注意到这里并没有正式的函数声明;单词get后跟一对花括号,里面是函数体。

③getter函数必须要返回与变量类型相同的值。

④setter函数叫作set。这里并没有正式的函数声明;单词set后跟一对花括号,里面是函数体。

⑤setter的行为就像是接收一个参数的函数。在默认情况下,参数通过局部名newValue进入setter函数中。

如下代码演示了计算变量的用法,这与其他变量没什么大的差别。该赋值时就赋值,该使用时就使用。不过在幕后,setter与getter函数会被调用:


now = /"Howdy/" // Howdy ①print(now) // 2015-06-26 17:03:30 +0000 ②  

①为now赋值会调用其setter。传递给调用的参数就是所赋的值,这里就是/"Howdy/"。该值进入set函数后成为newValue。set函数会将newValue打印到控制台上。

②获取now会调用其getter。get函数会获取到当前的日期时间,然后将其转换为字符串并返回。接下来将该字符串打印到控制台上。

注意到第1行将now设为/"Howdy/"时,字符串/"Howdy/"并没有存储下来。比如,它对于第2行的now值就没起任何作用。set函数可以存储值,不过它无法将其存储到计算变量中;计算变量是不可存储的!它只是调用getter与setter函数的便捷方法而已。

上述语法有几个变种:

·set函数的参数名不一定非得叫作newValue。要想指定不同的名字,将其放到单词set后面的圆括号中即可,如下代码所示:


set (val) { // now you can use /"val/" inside the setter function body  

·不一定要有setter。如果省略setter,那么变量就变成只读的了。为其赋值会导致编译器报错。没有setter的计算变量是Swift中创建只读变量的主要方式。

·一定要有getter!如果没有setter,那么单词get与后面的花括号就可以省略了。如下代码是声明只读变量的合法方式:


var now : String {    return NSDate.description}  

计算变量在很多地方都很有用。下面是其在实际使用中经常用到的地方:

只读变量

计算变量是创建只读变量最简单的方式,只需在声明中省略setter即可。通常情况下,变量是全局变量或属性;局部只读变量的意义并不大。

函数门面

如果每次需要一个值时,它都会由一个函数计算出来,那么可以通过更简单的语法将其表示为一个只读的计算变量。如下示例来自我所编写的代码:


var mp : MPMusicPlayerController {    return MPMusicPlayerController.systemMusicPlayer}  

每次想要引用时,都可以调用MPMusicPlayerController.systemMusicPlayer(),通过简单的名字mp来引用会更加紧凑一些。mp表示一个事物而非动作表现,因此将mp当作变量会更好一些,这样在所有出现mp的地方,它都表示一个事物而非返回事物的函数。

其他变量的门面

计算变量可以位于存储变量之前,作为一个守护者,来确定如何设置和获取那些存储变量。这是相比于Objective-C的访问器方法的。在极端情况下,公开的计算变量是由一个私有的存储变量所维护的:


private var _p : String = /"/"var p : String {    get {        return self._p    }    set {        self._p = newValue    }}  

这个示例本身没什么意义,因为对于访问器没什么可做的:我们只是直接设置和获取私有的存储变量而已,因此p与_p之间并没有什么实际的差别。但是基于该模板,你可以添加一些功能,在设置和获取时完成一些额外的事情。

正如上面的示例所示,计算实例属性函数可以引用其他实例属性,还可以调用实例方法。这是很重要的,因为一般来说,存储属性的初始化器这两件事都做不了。计算属性之所以可以,是因为直到实例存在了才可以调用它的函数。

如下示例演示了如何将计算变量用作存储门面。类有一个实例属性,它存储的数据很大,并且可以为nil(它是一个Optional,稍后将会介绍):


var myBigDataReal : NSData! = nil  

当应用进入后台时,我想减少内存使用(因为iOS会杀掉占据大量内存的后台应用)。因此,我计划将myBigDataReal数据保存为文件并存储到磁盘上,然后将变量本身设为nil,这样可以释放内存中的数据。现在来考虑当应用回到前台,并且代码尝试获取myBigDataReal时会发生什么。如果它不为nil,那么我们只需获取其值即可。但如果它为nil,可能是因为我们将其值保存到了磁盘上。现在我想读取磁盘来恢复其值,然后获取。这正是计算变量门面的用武之地:


var myBigData : NSData! {    set (newdata) {        self.myBigDataReal = newdata    }    get {        if myBigDataReal == nil {            // ... get a reference to file on disk, f ...            self.myBigDataReal = NSData(contentsOfFile: f)            // ... erase the file ...        }        return self.myBigDataReal    }}