Swift中屬性(Property)的分類

在Swift的學(xué)習(xí)過程中,我發(fā)現(xiàn)理解屬性,對后續(xù)學(xué)習(xí)類(Class)、枚舉(Enumeration)和協(xié)議(Protocol)很有幫助,現(xiàn)在總結(jié)一下Swift中屬性的分類,主要分為四大類:

  1. 存儲實例屬性(Stored Instance Property):存儲在實例的內(nèi)存中的屬性,只有一份

  2. 計算實例屬性(Computed Instance Property):不占用系統(tǒng)內(nèi)存,調(diào)用的時候才計算得出的實例屬性,類似實例的方法

  3. 存儲類型屬性(Stored Type Property):整個程序運行過程中就只有一份內(nèi)存,類似全局變量或常量

  4. 計算類型屬性(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語句,則可以省掉returnget關(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)鍵字willSetdidSet,還有延遲屬性(lazy properties),理解屬性分類后再去學(xué)習(xí)這些內(nèi)容會容易很多。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。