Swift学习笔记10——属性(Properties)

Swift中,属性大致分为两种,一种叫存储属性,一种叫计算属性。

所谓的存储属性,就是能保存数据的属性。枚举类、结构体、类都具有存储属性。

计算属性就是它本身不保存数据,而是通过处理其他的数据得到返回值。 结构体和类才具有计算属性。

存储属性(Stored Properties

先来看存储属性,存储属性可以设为var 或let。分别对应常量和变量。

struct CPU {
    var clockSpeed = 1.0   //变量
    let coreNum = 2        //常量
}

然后我们初始化一个CPU实例,但是这个实例我们设置为常量。这样会导致一个后果:对应值传递的结构体,当实例是常量的时候,即使存储属性是变量,也不能修改里面属性的值。

let cpu = CPU(clockSpeed: 3.2)   //注意到这个初始化方法只有一个参数,因为我们设置了coreNum为常量,并且给了初始值,所以构造方法会发生变化
cpu.clockSpeed = 3.3      //这句会报错


然而对于引用传递的类来讲,即使实例是常量,里面设置为变量的存储属性还是可以更改值的。

class Telephone {
    var cpu = CPU()
    var screenSize: Int?
    var price: Int?
}
let myTelephont = Telephone()
myTelephont.screenSize = 4

懒加载存储属性

这里先提早说一下,Swift需要保证一个类或结构体或枚举类在初始化之后,所以的存储属性都必须有初始值(除开可选类型)。所以当实例初始化完成以后,所以的存储属性都初始化了。但是有些时候某些存储属性不一定会用到,所以我们可以把这些存储属性设置为lazy存储属性。那么它在要用到的时候才会进行初始化。lazy存储属性只能是变量。而且在多线程调用的时候,如果lazy属性没有初始化,那么不能保证只会初始化一次。

struct CPU {
    lazy var clockSpeed = 1.0
    let coreNum = 2
}

let cpu = CPU()  //这时候clockSpeed还是为nil



计算属性(Computed Properties

故名思议,它本身不保存数据,只是用其他数据得到返回值,或者当设置它的时候修改其他数据。下面的例子利用存储属性得到apple的总价。或者修改总价的时候修改重量。

struct Apple {
    let pricePerKg = 6.0
    var weight: Double
    var totalPrice: Double {
        get {
            return pricePerKg * weight
        }
        set(newTotalPrice) {
            weight = newTotalPrice / pricePerKg
        }
    }
}

var apple = Apple(weight: 2.0)
print(apple.totalPrice)    //12.0
apple.totalPrice = 6.0
print(apple.weight)       //1.0

计算属性的setter方法新值自带一个默认名 newValue,所以上面的定义可以改为

struct Apple {
    let pricePerKg = 6.0
    var weight: Double
    var totalPrice: Double {
        get {
            return pricePerKg * weight
        }
        set {
            weight = newValue / pricePerKg
        }
    }
}

你还可以将计算属性的setter去掉,那么这个计算数据就变成了只读的。这时候还可以省去get关键字

struct Apple {
    let pricePerKg = 6.0
    var weight: Double
    var totalPrice: Double {
        return pricePerKg * weight
    }
}

注意一点,不要在计算属性的setter和getter里面获取该计算属性,这样会导致循环调用。


属性观察器(Property Observers

有了属性观察器,我们可以在属性被修改的时候做一些事情。注意的是对于非继承而来的计算属性,没有必要设置属性观察器,因为直接可以在计算属性的setter定义中完成这项功能。

属性观察器有两个方法

willSet 在属性将要赋值的时候调用,这时候属性的值还没改变

didSet在属性值被赋值完的时候就会调用。(即使是赋值和原来值一样的值)这时候属性的值已经改变。


willSet方法里面会传递新值过来,你可以自己定义这个新值的名称,如果不定义,会具有默认值newValue

didSet方法里面会传递属性的旧值过来,你可以自己定义这个旧值的名称,如果不定义,会具有默认值oldValue。如果你在didSet方法里面又对这个存储属性赋值,那么这个值会覆盖掉刚刚赋值的值。且不会导致循环调用。比如下面例子里面,当pricePerKg小于3的时候,会把它改为3.

struct Apple {
    var pricePerKg = 6.0 {
        willSet(priceNewValue){
            print("In willSet, priceNewValue=",priceNewValue)
            print("In willSet, pricePerKg=",pricePerKg)
        }
        didSet{
            print("In didSet, oldValue=",oldValue)
            print("In didSet, pricePerKg=",pricePerKg)
            if pricePerKg < 3 {
                pricePerKg = 3
            }
        }
    }
    var weight: Double
    var totalPrice: Double {
        get {
            return pricePerKg * weight
        }
        set {
            weight = newValue / pricePerKg
        }
    }
}

var apple = Apple(pricePerKg: 6.0, weight: 1.0)
apple.pricePerKg = 2.0
print("apple.pricePerKg=",apple.pricePerKg)
/* 输出
In willSet, priceNewValue= 2.0
In willSet, pricePerKg= 6.0
In didSet, oldValue= 6.0
In didSet, pricePerKg= 2.0
apple.pricePerKg= 3.0
*/


全局变量和局部变量(

Global and Local Variables

所谓的局部变量,就是定义在函数、方法、闭包、类型上下文里面的变量。

全局变量就是定义在函数、方法、闭包、类型上下文之外的变量。

局部变量和全局变量都称为存储变量。

在全局和局部范围内,都可以定义计算变量,或者为存储变量定义观察器。

var apple = Apple(pricePerKg: 6.0, weight: 1.0) {  //为apple变量定义观察器
willSet {
    print("newApple",newValue)
}
didSet{
    print("oldApple",oldValue)
}
}

apple = Apple(pricePerKg: 6.0, weight: 2.0)

var c: Double {  //定义一个计算变量
get{
    return 9
}
set {
    print("In setter,",newValue)
}
}
c = 2
print(c)
/*
newApple Apple(pricePerKg: 6.0, weight: 2.0)
oldApple Apple(pricePerKg: 6.0, weight: 1.0)
In setter, 2.0
9.0
*/


官方文档说全局变量常量都是懒加载,局部变量常量都不是懒加载。 这一点我还没验证出来


类型属性(

Type Properties

所谓的类型属性,就是这个属性是属于这个类型的,即使这个类型由多个实例,也只会有一个类型变量。

类型属性是懒加载的,而且必须在定义的时候给初始值。

一般是用static来定义类型属性。特别的,对应类的计算类型属性,还可以用class关键字定义,这样可以使得子类可以覆盖它。

注意类型属性访问的时候用的是类名,不能使用实例来访问。

struct SomeStructure {
    static var storedTypeProperty = "Some value."
    static var computedTypeProperty: Int {
        return 1
    }
}
enum SomeEnumeration {
    static var storedTypeProperty = "Some value."
    static var computedTypeProperty: Int {
        return 6
    }
}
class SomeClass {
    static var storedTypeProperty = "Some value."
    static var computedTypeProperty: Int {
        return 27
    }
    class var overrideableComputedTypeProperty: Int {
        return 107
    }
}

print(SomeStructure.storedTypeProperty)
// prints "Some value."
SomeStructure.storedTypeProperty = "Another value."
print(SomeStructure.storedTypeProperty)
// prints "Another value."
print(SomeEnumeration.computedTypeProperty)
// prints "6"
print(SomeClass.computedTypeProperty)
// prints "27"


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值