Swift 屬性
Swift 屬性将值跟特定的類、結構或枚舉關聯。
屬性可分為存儲屬性和計算屬性:
存儲屬性 計算屬性
存儲常量或變量作為執行個體的一部分 計算(而不是存儲)一個值
用于類和結構體 用于類、結構體和枚舉
存儲屬性和計算屬性通常用于特定類型的執行個體。
屬性也可以直接用于類型本身,這種屬性稱為類型屬性。
另外,還可以定義屬性觀察器來監控屬性值的變化,以此來觸發一個自定義的操作。屬性觀察器可以添加到自己寫的存儲屬性上,也可以添加到從父類繼承的屬性上。
存儲屬性
簡單來說,一個存儲屬性就是存儲在特定類或結構體的執行個體裡的一個常量或變量。
存儲屬性可以是變量存儲屬性(用關鍵字var定義),也可以是常量存儲屬性(用關鍵字let定義)。
可以在定義存儲屬性的時候指定預設值
也可以在構造過程中設定或修改存儲屬性的值,甚至修改常量存儲屬性的值
import Cocoa
struct Number
{
var digits: Int
let pi = 3.1415
}
var n = Number(digits: 12345)
n.digits = 67
print("\(n.digits)")
print("\(n.pi)")
以上程式執行輸出結果為:
67
3.1415
考慮以下代碼:
let pi = 3.1415
代碼中 pi 在定義存儲屬性的時候指定預設值(pi = 3.1415),是以不管你什麼時候執行個體化結構體,它都不會改變。
如果你定義的是一個常量存儲屬性,如果嘗試修改它就會報錯,如下所示:
var digits: Int
let numbers = 3.1415
print("\(n.numbers)")
n.numbers = 8.7
以上程式,執行會報錯,錯誤如下所示:
error: cannot assign to property: 'numbers' is a 'let' constant
意思為 'numbers' 是一個常量,你不能修改它。
延遲存儲屬性
延遲存儲屬性是指當第一次被調用的時候才會計算其初始值的屬性。
在屬性聲明前使用 lazy 來标示一個延遲存儲屬性。
注意:
必須将延遲存儲屬性聲明成變量(使用var關鍵字),因為屬性的值在執行個體構造完成之前可能無法得到。而常量屬性在構造過程完成之前必須要有初始值,是以無法聲明成延遲屬性。
延遲存儲屬性一般用于:
延遲對象的建立。
當屬性的值依賴于其他未知類
class sample {
lazy var no = number() // `var` 關鍵字是必須的
class number {
var name = "swift "
var firstsample = sample()
print(firstsample.no.name)
執行個體化變量
如果您有過 Objective-C 經驗,應該知道Objective-C 為類執行個體存儲值和引用提供兩種方法。對于屬性來說,也可以使用執行個體變量作為屬性值的後端存儲。
Swift 程式設計語言中把這些理論統一用屬性來實作。Swift 中的屬性沒有對應的執行個體變量,屬性的後端存儲也無法直接通路。這就避免了不同場景下通路方式的困擾,同時也将屬性的定義簡化成一個語句。
一個類型中屬性的全部資訊——包括命名、類型和記憶體管理特征——都在唯一一個地方(類型定義中)定義。
計算屬性
除存儲屬性外,類、結構體和枚舉可以定義計算屬性,計算屬性不直接存儲值,而是提供一個 getter 來擷取值,一個可選的 setter 來間接設定其他屬性或變量的值。
var no1 = 0.0, no2 = 0.0
var length = 300.0, breadth = 150.0
var middle: (Double, Double) {
get{
return (length / 2, breadth / 2)
}
set(axis){
no1 = axis.0 - (length / 2)
no2 = axis.1 - (breadth / 2)
}
var result = sample()
print(result.middle)
result.middle = (0.0, 10.0)
print(result.no1)
print(result.no2)
(150.0, 75.0)
-150.0
-65.0
如果計算屬性的 setter 沒有定義表示新值的參數名,則可以使用預設名稱 newValue。
隻讀計算屬性
隻有 getter 沒有 setter 的計算屬性就是隻讀計算屬性。
隻讀計算屬性總是傳回一個值,可以通過點(.)運算符通路,但不能設定新的值。
class film {
var head = ""
var duration = 0.0
var metaInfo: [String:String] {
return [
"head": self.head,
"duration":"\(self.duration)"
]
var movie = film()
movie.head = "Swift 屬性"
movie.duration = 3.09
print(movie.metaInfo["head"]!)
print(movie.metaInfo["duration"]!)
3.09
必須使用var關鍵字定義計算屬性,包括隻讀計算屬性,因為它們的值不是固定的。let關鍵字隻用來聲明常量屬性,表示初始化後再也無法修改的值。
屬性觀察器
屬性觀察器監控和響應屬性值的變化,每次屬性被設定值的時候都會調用屬性觀察器,甚至新的值和現在的值相同的時候也不例外。
可以為除了延遲存儲屬性之外的其他存儲屬性添加屬性觀察器,也可以通過重載屬性的方式為繼承的屬性(包括存儲屬性和計算屬性)添加屬性觀察器。
不需要為無法重載的計算屬性添加屬性觀察器,因為可以通過 setter 直接監控和響應值的變化。
可以為屬性添加如下的一個或全部觀察器:
willSet在設定新的值之前調用
didSet在新的值被設定之後立即調用
willSet和didSet觀察器在屬性初始化過程中不會被調用
class Samplepgm {
var counter: Int = 0{
willSet(newTotal){
print("計數器: \(newTotal)")
didSet{
if counter > oldValue {
print("新增數 \(counter - oldValue)")
}
let NewCounter = Samplepgm()
NewCounter.counter = 100
NewCounter.counter = 800
計數器: 100
新增數 100
計數器: 800
新增數 700
全局變量和局部變量
計算屬性和屬性觀察器所描述的模式也可以用于全局變量和局部變量。
局部變量 全局變量
在函數、方法或閉包内部定義的變量。 函數、方法、閉包或任何類型之外定義的變量。
用于存儲和檢索值。 用于存儲和檢索值。
存儲屬性用于擷取和設定值。 存儲屬性用于擷取和設定值。
也用于計算屬性。 也用于計算屬性。
類型屬性
類型屬性是作為類型定義的一部分寫在類型最外層的花括号({})内。
使用關鍵字 static 來定義值類型的類型屬性,關鍵字 class 來為類定義類型屬性。
struct Structname {
static var storedTypeProperty = " "
static var computedTypeProperty: Int {
// 這裡傳回一個 Int 值
}
enum Enumname {
class Classname {
class var computedTypeProperty: Int {
例子中的計算型類型屬性是隻讀的,但也可以定義可讀可寫的計算型類型屬性,跟執行個體計算屬性的文法類似。
擷取和設定類型屬性的值
類似于執行個體的屬性,類型屬性的通路也是通過點運算符(.)來進行。但是,類型屬性是通過類型本身來擷取和設定,而不是通過執行個體。執行個體如下:
struct StudMarks {
static let markCount = 97
static var totalCount = 0
var InternalMarks: Int = 0 {
didSet {
if InternalMarks > StudMarks.markCount {
InternalMarks = StudMarks.markCount
}
if InternalMarks > StudMarks.totalCount {
StudMarks.totalCount = InternalMarks
}
var stud1Mark1 = StudMarks()
var stud1Mark2 = StudMarks()
stud1Mark1.InternalMarks = 98
print(stud1Mark1.InternalMarks)
stud1Mark2.InternalMarks = 87
print(stud1Mark2.InternalMarks)
97
87