天天看點

18.Swift學習之屬性與方法

類的屬性介紹

  • Swift中屬性有多種
    • 存儲屬性:存儲執行個體的常量和變量
    • 計算屬性:通過某種方式計算出來的屬性
    • 類屬性:與整個類自身相關的屬性

存儲屬性

  • 存儲屬性是最簡單的屬性,它作為類執行個體的一部分,用于存儲常量和變量
  • 可以給存儲屬性提供一個預設值,也可以在初始化方法中對其進行初始化
  • 下面是存儲屬性的寫法
    • age和name都是存儲屬性,用來記錄該學生的年齡和姓名
    • chineseScore和mathScore也是存儲屬性,用來記錄該學生的國文分數和數學分數
class Student  {
    // 存儲屬性
    var age : Int = 0
    var name : String?

    var chineseScore : Double = 0.0
    var mathScore : Double = 0.0
}

// 建立學生對象
let stu = Student()

// 給存儲屬性指派
stu.age = 10
stu.name = "why"

stu.chineseScore = 89.0
stu.mathScore = 98.0
           

計算屬性

  • 計算屬性并不存儲實際的值,而是提供一個

    getter

    和一個可選的

    setter

    來間接擷取和設定其它屬性
  • 計算屬性一般隻提供

    getter

    方法
  • 如果隻提供

    getter

    ,而不提供

    setter

    ,則該計算屬性為隻讀屬性,并且可以省略

    get{}

  • 下面是計算屬性的寫法
    • averageScore是計算屬性,通過chineseScore和mathScore計算而來的屬性
    • 在setter方法中有一個newValue變量,是系統指定配置設定的
class Student {
    // 存儲屬性
    var age : Int = 0
    var name : String?

    var chineseScore : Double = 0.0
    var mathScore : Double = 0.0

    // 計算屬性
    var averageScore : Double {
        get {
            return (chineseScore + mathScore) / 2
        }

        // 死循環,在内部又會調用set方法
        // newValue是系統配置設定的變量名,内部存儲着新值
        set {
            self.averageScore = newValue
        }
    }
}

// 擷取計算屬性的值
print(stu.averageScore)
           

類屬性

  • 類屬性是與類相關聯的,而不是與類的執行個體相關聯
  • 所有的類和執行個體都共有一份類屬性.是以在某一處修改之後,該類屬性就會被修改
  • 類屬性的設定和修改,需要通過類來完成
  • 下面是類屬性的寫法
    • 類屬性可以使用

      static

      來修飾
    • courseCount是類屬性,用來記錄學生有多少門課程
class Student  {
    // 存儲屬性
    var age : Int = 0
    var name : String?

    var chineseScore : Double = 0.0
    var mathScore : Double = 0.0

    // 計算屬性
    var averageScore : Double {
       return (chineseScore + mathScore) / 2
    }

    // 類屬性
    static var englishScore:Double = 95.5
}

// 設定類屬性的值
Student.englishScore = 90.5
// 取出類屬性的值
print(Student.englishScore)
           

懶加載屬性

  • 蘋果的設計思想:希望所有的對象在使用時才真正加載到記憶體中
  • 在OC中我們可以重寫get方法來進行懶加載
  • Swift用

    lazy

    關鍵字可以用于定義某一個屬性懶加載
  • lazy的作用是隻會指派一次
  • 懶加載的本質是,在第一次使用的時候執行閉包,将閉包的傳回值指派給屬性

懶加載的使用

  • 格式
lazy var 變量: 類型 = { 建立變量代碼 }()
           
  • 案例
lazy var teacher:[String] = {    
        ()->[String] in   
        return ["Mr Zhang", "Mr Li", "Mr Yang"]
    }()

student.teacher
           

幾種屬性的差別

  • 存儲屬性 —— 實實在在存儲常量和變量的
  • 計算屬性 —— 依賴于存儲屬性,通過計算得出來,它提供getter和setter方法間接通路和設定值
  • 類屬性 —— 本質是一個全局屬性,在類裡限定了其作用域,用關鍵字static修飾
  • 懶加載屬性 —— 用關鍵字lazy修飾,必須進行初始化,非執行個體屬性懶加載時在大括号{}後面要加上()
  • 全局屬性 —— 類外面的屬性,作用域全局
  • 總結:
    • 存儲屬性,最先被初始化
    • 構造方法,僅次于存儲屬性調用,可以在這裡對存儲屬性進行指派
    • 懶加載屬性、類屬性、全局屬性都是在第一次使用的時候初始化一次,以後調用都不再初始化
    • 當懶加載屬性是基于一個存儲屬性計算的時候,切勿使用懶加載屬性,采用計算屬性

監聽屬性的改變

  • 在OC中我們可以重寫set方法來監聽屬性的改變
  • Swift中可以通過屬性觀察者來監聽和響應屬性值的變化
  • 通常是監聽存儲屬性和類屬性的改變.(對于計算屬性,不需要定義屬性觀察者,因為可以在計算屬性的setter中直接觀察并響應這種值的變化)
  • 定義觀察者
    • willSet:在屬性值被存儲之前設定。此時新屬性值作為一個常量參數被傳入。該參數名預設為newValue,可以自定義
    • didSet:在新屬性值被存儲後立即調用。與willSet相同,此時傳入的是屬性的舊值,預設參數名為oldValue,可以自定義
    • willSet與didSet隻有在屬性改變時才會調用,在初始化時不會去調用這些監聽方法
class Student {
    var name:String?{
        // 屬性即将改變,還未改變時會調用的方法
        // 可以給newValue自定義名稱
        willSet(new){
            print("willSet---")
            // 在該方法中有一個預設的系統屬性newValue,用于存儲新值
            if let new = new {
                 print(new)
            }
        }
        
        // 屬性值已經改變了,會調用的方法
        didSet{
            print("didSet---")
            // 在該方法中有一個預設的系統屬性oldValue,用于存儲舊值
            if let oldValue = oldValue {
                print(oldValue)
            }
        }
    }
}
var student = Student()
// 在指派時,監聽該屬性的改變
student.name = "Zhangsan"
student.name = "Lisi"
           

屬性繼承與重寫

  • 屬性繼承:子類可以繼承父類的屬性,包括存儲屬性、計算屬性和類型屬性,還可以繼承父類的屬性觀察器。
  • 屬性重寫
    • 無論繼承的是存儲屬性還是計算屬性,子類都可以通過提供getter和setter對屬性進行重寫
    • 可以将一個繼承的屬性重寫為一個讀寫屬性
    • 不可以将繼承來的讀寫屬性重寫為隻讀屬性
    • 如果重寫時提供了setter方法,一定要提供getter方法
  • 屬性觀察器重寫
    • 無論父類有沒有為該屬性添加屬性觀察器,子類都可以添加屬性觀察器
    • 如果父類已經添加了屬性觀察器,當屬性發生變化時,父類與子類都會得到通知
    • 屬性觀察器不能用于計算屬性,隻能用于存儲屬性,因為計算屬性在setter裡就可以擷取到屬性的變化

執行個體方法

  • 執行個體方法屬于特定類執行個體、結構體執行個體或者枚舉執行個體的函數
  • 這裡的方法其實就是函數,隻不過放在類、結構體和枚舉中時稱之為方法

self 屬性

  • 每一個類的執行個體都隐含一個叫做 self的屬性,可以使用 self通路目前類中的屬性和方法
class Student {   
    var str = "Hello, playground"
    func say(info:String) {
        print(info)
    } 
    func eat(food:String){
        //self指向的是目前類的執行個體
        self.say(info: food)
        print("吃\(food)")
    }
}
var stu = Student()
stu.eat(food: "米飯")
           

值類型在執行個體方法中修改屬性和調用方法

  • 值類型預設情況下,不能在執行個體方法中修改屬性
  • 不能用self調用其他的函數
  • 可以在函數前放一個

    mutating

    關鍵字來實作
struct Student {
    var str = "Hello, playground"
    mutating func say(info:String) {
        print(info)
        self.str = "Hello World"
        print(self.str)
    }
    mutating func eat(food:String){
        self.say(info: food)
        print("吃\(food)")
    }
}
           

類型方法

  • 在函數前使用 static關鍵字(能在類、結構體中使用)
  • 在函數前使用 class關鍵字(隻能在類中使用)
static func play(){    
   print("play")     
}
class func study(){      
   print("study")
}
           

class 和 static 總結

  • class 和 static 相同點
    • 可以修飾方法,static 修飾的方法叫做靜态方法,class修飾的叫做類方法
    • 都可以修飾計算屬性
  • class 和 static 不同點
    • class 不能修飾存儲屬性,static 可以修飾存儲屬性,static修飾的存儲屬性稱為靜态變量(常量)
    • class 修飾的計算屬性可以被重寫,static 修飾的不能被重寫
    • static 修飾的靜态方法不能被重寫,class 修飾的類方法可以被重寫
    • class 修飾的類方法被重寫時,可以使用static 讓方法變為靜态方法
    • class 修飾的計算屬性被重寫時,可以使用static 讓其變為靜态屬性,但它的子類就不能被重寫了
    • class 隻能在類中使用,但是static 可以在類,結構體,或者枚舉中使用