在Swift的學(xué)習(xí)過程中,我發(fā)現(xiàn)理解屬性,對后續(xù)學(xué)習(xí)類(Class)、枚舉(Enumeration)和協(xié)議(Protocol)很有幫助,現(xiàn)在總結(jié)一下Swift中屬性的分類,主要分為四大類:
存儲實例屬性(Stored Instance Property):存儲在實例的內(nèi)存中的屬性,只有一份
計算實例屬性(Computed Instance Property):不占用系統(tǒng)內(nèi)存,調(diào)用的時候才計算得出的實例屬性,類似實例的方法
存儲類型屬性(Stored Type Property):整個程序運行過程中就只有一份內(nèi)存,類似全局變量或常量
計算類型屬性(Computed Type Property):不占用系統(tǒng)內(nèi)存,調(diào)用的時候才計算得出的屬性,類似全局函數(shù)
下面分別詳細(xì)的總結(jié)一下:
存儲實例屬性:
- 類(class)和結(jié)構(gòu)體(struct)都可以定義存儲屬性,可以是變量
var
或者常數(shù)let
,而枚舉(enum)內(nèi)不能定義存儲實例屬性:
enum Animal {
case dog
var cat = "Cat" // Enums must not contain stored properties
}
- 創(chuàng)建類或者結(jié)構(gòu)體時,所有存儲實例屬性必須初始化(設(shè)置初始值或者在
init
中賦值),否則編譯不過:
class WrongAnimal {
let legs: Int
let eyes: Int
} // Class 'WrongAnimal' has no initializers
// 所有存儲實例屬性必須初始化:
class Animal {
let legs: Int = 4
let eyes: Int
init(eyes: Int ) {
self.eyes = eyes
}
}
var animal = Animal(eyes: 2)
-
extension
中不能定義存儲實例屬性:
extension Animal {
var ears: Int = 4 // Extensions must not contain stored properties
}
計算實例屬性:
- 類、結(jié)構(gòu)體、枚舉都可以定義計算實例屬性
- 計算屬性不存儲值,不用初始化,但至少需要提供一個getter(
get
)取值,setter(set
)賦值是可選的,比如:
struct Point {
var x: Double
var y: Double
var distanceToOrigin: Double {
get {
return sqrt(x * x + y * y)
}
}
}
let point = Point(x: 3, y: 4)
point.distanceToOrigin // 5
- 定義計算屬性只能使用
var
, 不能使用let
- 如果
get
中只有一條return
語句,則可以省掉return
和get
關(guān)鍵字,比如:
struct Point {
var x: Double
var y: Double
var distanceToOrigin: Double {
sqrt(x * x + y * y)
}
}
-
entension
可以定義計算屬性:
extension Point {
var z: Double { 1.0 }
}
- 可以在協(xié)議(
protocol
)的extension
中定義計算實例屬性,這樣相當(dāng)于實現(xiàn)了協(xié)議中的一個成員,比如:
protocol Game {
var win: Int { get set }
var lose: Int { get set }
}
extension Game {
var winRate: Double {
Double(win) / (Double(win) + Double(lose))
}
}
struct FootballGame: Game {
var win: Int
var lose: Int
}
let footballGame = FootballGame(win: 8, lose: 2)
footballGame.winRate // 0.8
- 枚舉的
rawValue
的本質(zhì)就是實例計算屬性, 而且是只讀的計算屬性:
enum Color: Int {
case red = 1
case blue = 2
case yellow = 3
}
Color.blue.rawValue // 2
Color.yellow.rawValue = 4 // Cannot assign to property: 'rawValue' is immutable
- 我們可以在
enum
重新定義rawValue
計算屬性:
enum Color: Int {
case red = 1
case blue = 2
case yellow = 3
var rawValue: Int {
switch self {
case .red:
return 10
case .blue:
return 20
case .yellow:
return 30
}
}
}
Color.blue.rawValue // 20
存儲類型類型屬性:
- 類、結(jié)構(gòu)體、枚舉中使用
static
定義
struct Storage {
static let books = 10
static var money = 20
}
Store.books // 10
Store.money = 30
- 存儲類型類型屬性必須有初始值,不用使用init初始化
- 存儲類型類型只會在第一次使用的時候初始化
- 存儲類型屬性不能在子類中被重寫
class Storage {
static let books = 10
static var money = 20
}
class LargeStorage: Storage {
static let books = 20 // Cannot override with a stored property 'books'
}
-
extension
中可以定義儲存類型屬性,我們可以用這種方法,擴展UIKit里常用的類,比如UIColor、UIFont等:
extension UIColor {
static let myColor = UIColor.init(red: 0.5, green: 0.5, blue: 0.5, alpha: 0.5)
}
UIColor.myColor
計算類型類型屬性:
- 類、結(jié)構(gòu)體、枚舉中使用
static
定義計算類型屬性,類中還可以使用class
關(guān)鍵字定義
class Storage {
static let books = 10
class var money: Double {
20
}
}
- 同計算實例屬性一樣,定義計算屬性只能使用
var
, 不能使用let
- 使用
class
關(guān)鍵字時,計算類型屬性可以在子類中被重寫:
class LargeStorage: Storage {
override class var money: Double {
30
}
}
-
extension
中可以定義計算類型屬性
總結(jié)
Swift中的屬性主要可以分為四大類:存儲實例屬性,計算實例屬性,存儲類型屬性,計算類型屬性。
進一步總結(jié),如果按內(nèi)存存儲方式分類,可以分為兩大類:存儲屬性(存儲在系統(tǒng)內(nèi)存中變量或者常量)和計算屬性(不占用內(nèi)存,類似函數(shù)),如果按屬性是屬于實例還是類,可以分為:實例屬性(屬于實例的屬性)和類型屬性(屬于類的屬性,用static
或者class
修飾)。
理解的屬性的分類,我們可以大概推出某類屬性的適用場景和規(guī)則,比如存儲實例屬性,因為要存儲在實例的內(nèi)存中,所以實例初始化的時候必須初始化全部的存儲屬性(optional類型除外),這也解釋了為什么extension
中為什么不能添加存儲實例屬性,因為如果這樣做了,那么這個屬性就必須存在于實例的內(nèi)存中,那之前所有已經(jīng)初始化的實例就必須全部修改,幾乎不可能實現(xiàn),所以extension中只能添加計算屬性或者存儲類型屬性。
理解分類后,以后看到一個屬性,大概知道這是什么類型的屬性,從而理解這個屬性設(shè)計者的意圖,加快理解代碼。
其實屬性還有很多內(nèi)容,比如屬性觀察器(property observers),對應(yīng)關(guān)鍵字willSet
和didSet
,還有延遲屬性(lazy properties),理解屬性分類后再去學(xué)習(xí)這些內(nèi)容會容易很多。