Swift4類和結構(二)

weixin_34393428發表於2017-12-11

屬性


定義

使用varlet定義

懶載入屬性

懶載入屬性是在首次用到的時候才載入,需要在宣告前標註lazy修飾語來標明一個懶載入屬性。

懶載入屬性只能宣告為變數(也就是使用var定義)
當屬性載入需要耗費很長時間的時候,使用懶載入就很有意義了。

class DataImporter {
/*
DataImporter 是從外部檔案匯入資料的類,該類的初始化需要很長時間。
*/
var filename = "data.txt"
// the DataImporter class would provide data importing functionality here
}
class DataManager {
lazy var importer = DataImporter()
var data = [String]()
// the DataManager class would provide data management functionality here
}
let manager = DataManager()
manager.data.append("Some data")
manager.data.append("Some more data")
// 此時DataManager的例項裡的importer屬性還沒有建立

因為它被 lazy 修飾符所標記,只有在 importer 屬性第一次被訪問時才會建立 DataManager 例項,比如當查詢它的fileName 屬性時:

print(manager.importer.fileName)

注意:如果被標記為 lazy 修飾符的屬性同時被多個執行緒訪問並且屬性還沒有被初始化,則無法保證屬性只初始化一次。

計算屬性

在getter或者setter裡用其他屬性值來生成屬性值或者改變其他屬性的值,叫做計算屬性。

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()
    var center: Point {
        get {
            let centerX = origin.x + (size.width / 2)
            let centerY = origin.y + (size.height / 2)
            return Point(x: centerX, y: centerY)
        }
        set(newCenter) {
            origin.x = newCenter.x - (size.width / 2)
            origin.y = newCenter.y - (size.height / 2)
        }
    }
}
var square = Rect(origin: Point(x: 0.0, y: 0.0),
    size: Size(width: 10.0, height: 10.0))
let initialSquareCenter = square.center
square.center = Point(x: 15.0, y: 15.0)
print("square.origin is now at (\(square.origin.x), \(square.origin.y))")
// prints "square.origin is now at (10.0, 10.0)"

簡寫setter宣告

如果計算屬性的setter沒有為將要設定的值定義一個名字,預設使用newValue

struct AlternativeRect {
    var origin = Point()
    var size = Size()
    var center: Point {
        get {
            let centerX = origin.x + (size.width / 2)
            let centerY = origin.y + (size.height / 2)
            return Point(x: centerX, y: centerY)
        }
        set {
            origin.x = newValue.x - (size.width / 2)
            origin.y = newValue.y - (size.height / 2)
        }
    }
}

只讀屬性

一個只有getter而沒有setter的屬性被稱為只讀屬性。
你可以通過去掉 get 關鍵字和他的大擴號來簡化只讀計算屬性的宣告

struct Cuboid {
    var width = 0.0, height = 0.0, depth = 0.0
    var volume: Double {
        return width * height * depth
    }
}
let fourByFiveByTwo = Cuboid(width: 4.0, height: 5.0, depth: 2.0)
print("the volume of fourByFiveByTwo is \(fourByFiveByTwo.volume)")
// prints "the volume of fourByFiveByTwo is 40.0"

屬性觀察者

類似資料庫的觸發器

  • willSet:屬性被儲存之前呼叫
  • didSet:屬性被儲存之後呼叫

如果你實現了一個 willSet 觀察者,新的屬性值會以常量形式引數傳遞。你可以在你的 willSet 實現中為這個引數定義名字。如果你沒有為它命名,那麼它會使用預設的名字 newValue

同樣,如果你實現了一個 didSet觀察者,一個包含舊屬性值的常量形式引數將會被傳遞。你可以為它命名,也可以使用預設的形式引數名 oldValue 。如果你在屬性自己的 didSet 觀察者裡給自己賦值,你賦值的新值就會取代剛剛設定的值.


class StepCounter {

    var totalSteps: Int = 0 {
        willSet(newTotalSteps) {
            print("About to set totalSteps to \(newTotalSteps)")
        }
        didSet {
            if totalSteps > oldValue  {
                print("Added \(totalSteps - oldValue) steps")
            }
        }
    }
}

方法


在例項方法中修改值型別

結構和列舉是值型別。預設情況下,結構和列舉裡的方法是不能修改自身的屬性的。
如果需要在結構和列舉裡使用自身的方法改變屬性的值,可以在方法前加上mutating關鍵字:

struct Point {
    var x = 0.0, y = 0.0
    mutating func moveBy(x deltaX: Double, y deltaY: Double) {
        x += deltaX
        y += deltaY
    }
}

型別方法

類似於其他語言中的類方法

  • 宣告結構體和列舉的型別方法使用關鍵字static
  • 宣告類的型別方法使用關鍵字class
class SomeClass {
    class func someTypeMethod() {
        // type method implementation goes here
    }
}
SomeClass.someTypeMethod()

下標


Swift的類,結構和列舉可以過載下標運算。
你可以為一個型別定義多個下標,並且下標會基於傳入的索引值的型別選擇合適的下標過載使用。下標沒有限制單個維度,你可以使用多個輸入形參來定義下標以滿足自定義型別的需求。

下標語法

使用關鍵字subscript定義下標運算,可以設定getter和setter方法讀寫下標,也可以設定只讀屬性。


// 下標可讀寫

subscript(index: Int) -> Int {
    get {
        // return an appropriate subscript value here
    }
    set(newValue) {
        // perform a suitable setting action here
    }
}

// 只讀

subscript(index: Int) -> Int {
    // return an appropriate subscript value here
}

下標選項

下標可以接收任意數量的輸入形式引數,並且這些輸入形式引數可以是任意型別。下標也可以返回任意型別。

類或結構體可以根據自身需要提供多個下標實現,合適被使用的下標會基於值型別或者使用下標時下標方括號裡包含的值來推斷。這個對多下標的定義就是所謂的下標過載。

例子定義一個矩陣結構


struct Matrix {

    let rows: Int, columns: Int
    var grid: [Double]
    init(rows: Int, columns: Int) {
        self.rows = rows
        self.columns = columns
        grid = Array(repeating: 0.0, count: rows * columns)
    }
    func indexIsValid(row: Int, column: Int) -> Bool {
        return row >= 0 && row < rows && column >= 0 && column < columns
    }
    subscript(row: Int, column: Int) -> Double {
        get {
            assert(indexIsValid(row: row, column: column), "Index out of range")
            return grid[(row * columns) + column]
        }
        set {
            assert(indexIsValid(row: row, column: column), "Index out of range")
            grid[(row * columns) + column] = newValue
        }
    }
}

繼承


swift的繼承語法

class SomeSubclass: SomeSuperclass {
    // subclass definition goes here
}

重寫

重寫必須新增關鍵字override否則會編譯錯誤

// 重寫方法
class Train: Vehicle {
    override func makeNoise() {
        print("Choo Choo")
    }
}
// 重寫屬性
class Car: Vehicle {
    var gear = 1
    override var description: String {
        return super.description + " in gear \(gear)"
    }
}

Super

使用super呼叫父類屬性或者方法

阻止重寫

使用final關鍵字

相關文章