屬性(Properties)

屬性將值跟特定的類(lèi)、結(jié)構(gòu)或枚舉關(guān)聯(lián)。

  • 存儲(chǔ)屬性: 存儲(chǔ)常量或變量作為實(shí)例的一部分。
    • 計(jì)算屬性可以用于 類(lèi)結(jié)構(gòu)體枚舉
  • 計(jì)算屬性: 計(jì)算(不是存儲(chǔ))一個(gè)值。
    • 存儲(chǔ)屬性只能用于 ** 類(lèi)** 和 結(jié)構(gòu)體。*

屬性分為 實(shí)例屬性類(lèi)型屬性

1. 存儲(chǔ)屬性

存儲(chǔ)屬性:就是存儲(chǔ)在特定類(lèi)或結(jié)構(gòu)體實(shí)例里的一個(gè) 常量變量。

  • 變量存儲(chǔ)屬性(用關(guān)鍵字 var 定義)
  • 常量存儲(chǔ)屬性(用關(guān)鍵字 let 定義)

** 存儲(chǔ)屬性的默認(rèn)值 **

  • 存儲(chǔ)屬性可以在定義的時(shí)候賦值默認(rèn)值。
  • 可以在構(gòu)造過(guò)程中設(shè)置和修改存儲(chǔ)屬性的值。(常量的值只可以在構(gòu)造函數(shù)中進(jìn)行修改)

常量結(jié)構(gòu)體的存儲(chǔ)屬性
創(chuàng)建了一個(gè)結(jié)構(gòu)體的實(shí)例并將其賦值給一個(gè)常量,則無(wú)法修改該實(shí)例的任何屬性,即使有屬性被聲明為變量也不行。
(常量結(jié)構(gòu)體的變量屬性是不能被修改的,這個(gè)是由于結(jié)構(gòu)體的值類(lèi)型決定)

** 延遲存儲(chǔ)屬性**
延遲存儲(chǔ)屬性是指 當(dāng)?shù)谝淮伪徽{(diào)用的時(shí)候 才會(huì)計(jì)算其 初始值 的屬性。在屬性聲明前使用 lazy 來(lái)標(biāo)示一個(gè)延遲存儲(chǔ)屬性。

  • 延遲存儲(chǔ)屬性必須用 var 聲明
  • 被標(biāo)記為 lazy 的屬性在沒(méi)有初始化時(shí)就同時(shí)被多個(gè)線程訪問(wèn),則無(wú)法保證該屬性只會(huì)被初始化一次。(加鎖)

實(shí)例屬性使用場(chǎng)景

  • 屬性值對(duì)實(shí)例的構(gòu)造過(guò)程不依賴(lài)
  • 屬性的值需要經(jīng)過(guò)大量計(jì)算才可以得到(耗時(shí))
    (加載本地文件數(shù)據(jù)就可以使用延遲屬性)

2. 計(jì)算屬性

  • ** 計(jì)算屬性不直接存儲(chǔ)值,**而是提供一個(gè) getter 和一個(gè)可選的 setter,來(lái)間接獲取和設(shè)置其他屬性或變量的值。
  • 計(jì)算屬性只能用 var 來(lái)聲明。(由于計(jì)算屬性值的不確定性決定)
struct Point {
    var x = 0.0, y = 0.0
}
struct Size {
    var width = 0.0, height = 0.0
}
struct Rect {
    var origin = Point()
    var size = Size()

    // 計(jì)算屬性, 中心點(diǎn)是依賴(lài) origin 和 size 計(jì)算得出具體的值。本身不能保存值。
    var center: Point {

        // getter
        get {
            let centerX = origin.x + (size.width / 2)
            let centerY = origin.y + (size.height / 2)
            return Point(x: centerX, y: centerY)
        }

        // setter (可選的)
        /**
          set 方法默認(rèn)有一個(gè)參數(shù)  newValue 用來(lái)表示我們傳入的值。
          我可以對(duì)set 的參數(shù)名稱(chēng)進(jìn)行進(jìn)行修改,增強(qiáng)代碼的可讀性。

          這個(gè)是 編輯 set 聲明的使用,直接使用 newValue 并且 set 的參數(shù)可以省略。
          set {
              origin.x = newValue.x - (size.width / 2)
              origin.y = newValue.y - (size.height / 2)
          }
        */
        set(newCenter) {
            origin.x = newCenter.x - (size.width / 2)
            origin.y = newCenter.y - (size.height / 2)
        }
    }
}

只讀計(jì)算屬性:
只有 getter 沒(méi)有 setter 的計(jì)算屬性就是只讀計(jì)算屬性。
(只讀計(jì)算屬性總是返回一個(gè)固定的值,不能賦新值)

struct Cuboid {
    var width = 0.0, height = 0.0, depth = 0.0
    
    // 只讀計(jì)算屬性,可以省略 get 個(gè)花括號(hào)
    var volume: Double {
        return width * height * depth
    }
}

3. 屬性觀察器(存儲(chǔ)屬性和計(jì)算屬性都可以添加屬性觀察器)

屬性觀察器監(jiān)控和響應(yīng)屬性值的變化,每次屬性被設(shè)置值的時(shí)候都會(huì)調(diào)用屬性觀察器,即使新值和當(dāng)前值相同。

  • 延遲存儲(chǔ)屬性 不能有 屬性觀察器。(重點(diǎn))
  • 可以通過(guò) 重寫(xiě) 屬性的方式為 繼承的屬性(包括存儲(chǔ)屬性和計(jì)算屬性)添加屬性觀察器。
  • 可以給所有的存儲(chǔ)屬性添加屬性觀察器。
  • 不必為 非重寫(xiě) (非繼承) 的 ** 計(jì)算屬性 ** 添加屬性觀察器,因?yàn)榭梢酝ㄟ^(guò)它的 setter 直接監(jiān)控和響應(yīng)值的變化。

理論上屬性觀察器是可以給所有的屬性添加。(不用區(qū)分是否是存儲(chǔ)是否是計(jì)算。主要是要區(qū)分一下使用的場(chǎng)景)

可以為屬性添加如下一個(gè)或多個(gè)屬性觀察器:

  • willSet: 在新的值被設(shè)置之前調(diào)用
    • willSet 觀察器會(huì)將新的屬性值作為 常量參數(shù) 傳入。
      在 willSet 的實(shí)現(xiàn)代碼中可以為這個(gè)參數(shù)指定一個(gè)名稱(chēng),不指定可以使用默認(rèn)參數(shù) newValue。
  • didSet: 在新的值被設(shè)置之后調(diào)用
    • didSet 觀察器會(huì)將舊值作為參數(shù)傳入。
      在 didSet 的實(shí)現(xiàn)代碼中可以為這個(gè)參數(shù)指定一個(gè)名稱(chēng), 不指定可以使用默認(rèn)的參數(shù) oldValue
class StepCounter {

    // 這是一個(gè)存儲(chǔ)屬性
    var totalSteps: Int = 0 {

        // willSet 屬性觀察器 , 指定的傳入?yún)?shù)名稱(chēng)為 newTotalSteps。
        /*
        // 這個(gè)為使用默認(rèn)參數(shù)
        willSet {
            print("About to set totalSteps to \(newValue)")
        }
        */
        willSet(newTotalSteps) {
            print("About to set totalSteps to \(newTotalSteps)")
        }


        /*
        // 自己定義一個(gè)參數(shù)使用,主要是為了代碼的語(yǔ)義化。
        didSet ( tempOldValue ) {
            // totalSteps 就是屬性本身。
            if totalSteps > tempOldValue  {
                print("Added \(totalSteps - tempOldValue) steps")
            }
        }
        */
        // 這個(gè)為使用默認(rèn)參數(shù)
        didSet {
            if totalSteps > oldValue  {
                print("Added \(totalSteps - oldValue) steps")
            }
        }
    }
}

存儲(chǔ)屬性的使用注意:

  • 父類(lèi)的屬性在子類(lèi)中賦值時(shí),父類(lèi)的 屬性觀察器會(huì)先被調(diào)用,后才會(huì)調(diào)用子類(lèi)的屬性觀察器。
    • 在父類(lèi)初始化方法調(diào)用之前,子類(lèi)給屬性賦值時(shí),觀察器不會(huì)被調(diào)用。
  • 屬性是通過(guò) in-out 方式傳入, 屬性觀察器也會(huì)被調(diào)用。
 * in-out 是用的是值的拷貝使用, 使用的是值的拷貝,值使用完畢后再將值拷貝出來(lái)。

4. 全局變量 和 局部變量

全局變量:是在函數(shù)、方法、閉包或任何類(lèi)型之外定義的變量。
局部變量:是在函數(shù)、方法或閉包內(nèi)部定義的變量。

全局或局部變量都屬于存儲(chǔ)型變量,跟存儲(chǔ)屬性類(lèi)似,它為特定類(lèi)型的值提供存儲(chǔ)空間,并允許讀取和寫(xiě)入。

在全局或局部范圍都可以定義計(jì)算型變量和為存儲(chǔ)型變量定義觀察器。計(jì)算型變量跟計(jì)算屬性一樣,返回一個(gè)計(jì)算結(jié)果而不是存儲(chǔ)值,聲明格式也完全一樣。

注意:
全局的常量或變量都是延遲計(jì)算的,跟延遲存儲(chǔ)屬性相似,不同的地方在于,全局的常量或變量不需要標(biāo)記lazy修飾符。
局部范圍的常量或變量從不延遲計(jì)算。

5. 類(lèi)型屬性

實(shí)例屬性: 特定類(lèi)型的實(shí)例的屬性叫實(shí)例屬性。實(shí)例之間的屬性是相互獨(dú)立的。
類(lèi)型屬性:特定類(lèi)型的屬性叫實(shí)例屬性。類(lèi)型之間的屬性是共享的。只有唯一一份。
(類(lèi)型屬性: 特么第一眼我也沒(méi)看明白。其實(shí)就是特么寫(xiě)在類(lèi)里面的靜態(tài)變量和靜態(tài)常量)

使用 static 來(lái)定義類(lèi)型屬性(靜態(tài)變量和靜態(tài)常量)。

定義計(jì)算型類(lèi)型屬性,可以改用 class 來(lái)支持子類(lèi)對(duì)父類(lèi)實(shí)現(xiàn)進(jìn)行重寫(xiě)。

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 表示不允許子類(lèi)重寫(xiě) 
   static var computedTypeProperty: Int {
        return 27
    }

    // 使用 class 表示允許子類(lèi)重寫(xiě)。
    class var overrideableComputedTypeProperty: Int {
        return 107
    }
}
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 屬性就是將值和特定的類(lèi)、結(jié)構(gòu)和枚舉進(jìn)行關(guān)聯(lián)。存儲(chǔ)屬性存儲(chǔ)常量(變量)來(lái)作為實(shí)例的一部分,而計(jì)算屬性不是存儲(chǔ)一個(gè)值。...
    Mustard_Buli閱讀 2,178評(píng)論 0 2
  • 計(jì)算屬性可以用于類(lèi)、結(jié)構(gòu)體和枚舉, 存儲(chǔ)屬性只能用于類(lèi)和結(jié)構(gòu)體。 枚舉只能有計(jì)算屬性 屬性觀察器可以添加到自己定義...
    松哥888閱讀 661評(píng)論 0 0
  • ?屬性:將值與特定的類(lèi)、結(jié)構(gòu)體或枚舉關(guān)聯(lián);?存儲(chǔ)屬性:存儲(chǔ)常量或變量作為實(shí)例的一部分;?計(jì)算屬性:用于計(jì)算一個(gè)值(...
    EndEvent閱讀 647評(píng)論 1 5
  • 常量與變量使用let來(lái)聲明常量,使用var來(lái)聲明變量。聲明的同時(shí)賦值的話,編譯器會(huì)自動(dòng)推斷類(lèi)型。值永遠(yuǎn)不會(huì)被隱式轉(zhuǎn)...
    莫_名閱讀 517評(píng)論 0 1
  • Swift語(yǔ)法基礎(chǔ)(五)-- (類(lèi)和結(jié)構(gòu)體、屬性、方法) 本章將會(huì)介紹 類(lèi)和結(jié)構(gòu)體對(duì)比結(jié)構(gòu)體和枚舉是值類(lèi)型類(lèi)是引用...
    寒橋閱讀 1,166評(píng)論 0 1

友情鏈接更多精彩內(nèi)容