在线观看不卡亚洲电影_亚洲妓女99综合网_91青青青亚洲娱乐在线观看_日韩无码高清综合久久

鍍金池/ 教程/ iOS/ 擴(kuò)展(Extensions)
方法 - Methods
關(guān)于 Swift
下標(biāo)腳本(Subscripts)
類和結(jié)構(gòu)體
類型轉(zhuǎn)換(Type Casting)
控制流
析構(gòu)過程(Deinitialization)
集合類型 (Collection Types)
構(gòu)造過程(Initialization)
Optional Chaining
枚舉(Enumerations)
自動引用計數(shù)
繼承(Inheritance)
擴(kuò)展(Extensions)
泛型
字符串和字符(Strings and Characters)
函數(shù)(Functions)
高級運(yùn)算符
訪問控制
基本運(yùn)算符
嵌套類型
閉包(Closures)
協(xié)議
屬性 (Properties)

擴(kuò)展(Extensions)

擴(kuò)展就是向一個已有的類、結(jié)構(gòu)體或枚舉類型添加新功能(functionality)。這包括在沒有權(quán)限獲取原始源代碼的情況下擴(kuò)展類型的能力(即逆向建模)。擴(kuò)展和 Objective-C 中的分類(categories)類似。(不過與Objective-C不同的是,Swift 的擴(kuò)展沒有名字。)

Swift 中的擴(kuò)展可以:

  • 添加計算型屬性和計算靜態(tài)屬性
  • 定義實例方法和類型方法
  • 提供新的構(gòu)造器
  • 定義下標(biāo)
  • 定義和使用新的嵌套類型
  • 使一個已有類型符合某個協(xié)議

注意:
如果你定義了一個擴(kuò)展向一個已有類型添加新功能,那么這個新功能對該類型的所有已有實例中都是可用的,即使它們是在你的這個擴(kuò)展的前面定義的。

擴(kuò)展語法(Extension Syntax)

聲明一個擴(kuò)展使用關(guān)鍵字extension

    extension SomeType {
        // 加到SomeType的新功能寫到這里
    }

一個擴(kuò)展可以擴(kuò)展一個已有類型,使其能夠適配一個或多個協(xié)議(protocol)。當(dāng)這種情況發(fā)生時,協(xié)議的名字應(yīng)該完全按照類或結(jié)構(gòu)體的名字的方式進(jìn)行書寫:

    extension SomeType: SomeProtocol, AnotherProctocol {
        // 協(xié)議實現(xiàn)寫到這里
    }

按照這種方式添加的協(xié)議遵循者(protocol conformance)被稱之為在擴(kuò)展中添加協(xié)議遵循者

計算型屬性(Computed Properties)

擴(kuò)展可以向已有類型添加計算型實例屬性和計算型類型屬性。下面的例子向 Swift 的內(nèi)建Double類型添加了5個計算型實例屬性,從而提供與距離單位協(xié)作的基本支持。

    extension Double {
        var km: Double { return self * 1_000.0 }
        var m : Double { return self }
        var cm: Double { return self / 100.0 }
        var mm: Double { return self / 1_000.0 }
        var ft: Double { return self / 3.28084 }
    }
    let oneInch = 25.4.mm
    println("One inch is \(oneInch) meters")
    // 打印輸出:"One inch is 0.0254 meters"
    let threeFeet = 3.ft
    println("Three feet is \(threeFeet) meters")
    // 打印輸出:"Three feet is 0.914399970739201 meters"

這些計算屬性表達(dá)的含義是把一個Double型的值看作是某單位下的長度值。即使它們被實現(xiàn)為計算型屬性,但這些屬性仍可以接一個帶有dot語法的浮點型字面值,而這恰恰是使用這些浮點型字面量實現(xiàn)距離轉(zhuǎn)換的方式。

在上述例子中,一個Double型的值1.0被用來表示“1米”。這就是為什么m計算型屬性返回self——表達(dá)式1.m被認(rèn)為是計算1.0Double值。

其它單位則需要一些轉(zhuǎn)換來表示在米下測量的值。1千米等于1,000米,所以km計算型屬性要把值乘以1_000.00來轉(zhuǎn)化成單位米下的數(shù)值。類似地,1米有3.28024英尺,所以ft計算型屬性要把對應(yīng)的Double值除以3.28024來實現(xiàn)英尺到米的單位換算。

這些屬性是只讀的計算型屬性,所有從簡考慮它們不用get關(guān)鍵字表示。它們的返回值是Double型,而且可以用于所有接受Double的數(shù)學(xué)計算中:

    let aMarathon = 42.km + 195.m
    println("A marathon is \(aMarathon) meters long")
    // 打印輸出:"A marathon is 42195.0 meters long"

注意:
擴(kuò)展可以添加新的計算屬性,但是不可以添加存儲屬性,也不可以向已有屬性添加屬性觀測器(property observers)。

構(gòu)造器(Initializers)

擴(kuò)展可以向已有類型添加新的構(gòu)造器。這可以讓你擴(kuò)展其它類型,將你自己的定制類型作為構(gòu)造器參數(shù),或者提供該類型的原始實現(xiàn)中沒有包含的額外初始化選項。

擴(kuò)展能向類中添加新的便利構(gòu)造器,但是它們不能向類中添加新的指定構(gòu)造器或析構(gòu)函數(shù)。指定構(gòu)造器和析構(gòu)函數(shù)必須總是由原始的類實現(xiàn)來提供。

注意:
如果你使用擴(kuò)展向一個值類型添加一個構(gòu)造器,在該值類型已經(jīng)向所有的存儲屬性提供默認(rèn)值,而且沒有定義任何定制構(gòu)造器(custom initializers)時,你可以在值類型的擴(kuò)展構(gòu)造器中調(diào)用默認(rèn)構(gòu)造器(default initializers)和逐一成員構(gòu)造器(memberwise initializers)。

正如在值類型的構(gòu)造器代理中描述的,如果你已經(jīng)把構(gòu)造器寫成值類型原始實現(xiàn)的一部分,上述規(guī)則不再適用。

下面的例子定義了一個用于描述幾何矩形的定制結(jié)構(gòu)體Rect。這個例子同時定義了兩個輔助結(jié)構(gòu)體SizePoint,它們都把0.0作為所有屬性的默認(rèn)值:

    struct Size {
        var width = 0.0, height = 0.0
    }
    struct Point {
        var x = 0.0, y = 0.0
    }
    struct Rect {
        var origin = Point()
        var size = Size()
    }

因為結(jié)構(gòu)體Rect提供了其所有屬性的默認(rèn)值,所以正如默認(rèn)構(gòu)造器中描述的,它可以自動接受一個默認(rèn)的構(gòu)造器和一個成員級構(gòu)造器。這些構(gòu)造器可以用于構(gòu)造新的Rect實例:

    let defaultRect = Rect()
    let memberwiseRect = Rect(origin: Point(x: 2.0, y: 2.0),
        size: Size(width: 5.0, height: 5.0))

你可以提供一個額外的使用特殊中心點和大小的構(gòu)造器來擴(kuò)展Rect結(jié)構(gòu)體:

    extension Rect {
        init(center: Point, size: Size) {
            let originX = center.x - (size.width / 2)
            let originY = center.y - (size.height / 2)
            self.init(origin: Point(x: originX, y: originY), size: size)
        }
    }

這個新的構(gòu)造器首先根據(jù)提供的centersize值計算一個合適的原點。然后調(diào)用該結(jié)構(gòu)體自動的成員構(gòu)造器init(origin:size:),該構(gòu)造器將新的原點和大小存到了合適的屬性中:

    let centerRect = Rect(center: Point(x: 4.0, y: 4.0),
        size: Size(width: 3.0, height: 3.0))
    // centerRect的原點是 (2.5, 2.5),大小是 (3.0, 3.0)

注意:
如果你使用擴(kuò)展提供了一個新的構(gòu)造器,你依舊有責(zé)任保證構(gòu)造過程能夠讓所有實例完全初始化。

方法(Methods)

擴(kuò)展可以向已有類型添加新的實例方法和類型方法。下面的例子向Int類型添加一個名為repetitions的新實例方法:

    extension Int {
        func repetitions(task: () -> ()) {
            for i in 0..<self {
                task()
            }
        }
    }

這個repetitions方法使用了一個() -> ()類型的單參數(shù)(single argument),表明函數(shù)沒有參數(shù)而且沒有返回值。

定義該擴(kuò)展之后,你就可以對任意整數(shù)調(diào)用repetitions方法,實現(xiàn)的功能則是多次執(zhí)行某任務(wù):

    3.repetitions({
        println("Hello!")
        })
    // Hello!
    // Hello!
    // Hello!

可以使用 trailing 閉包使調(diào)用更加簡潔:

    3.repetitions{
        println("Goodbye!")
    }
    // Goodbye!
    // Goodbye!
    // Goodbye!

修改實例方法(Mutating Instance Methods)

通過擴(kuò)展添加的實例方法也可以修改該實例本身。結(jié)構(gòu)體和枚舉類型中修改self或其屬性的方法必須將該實例方法標(biāo)注為mutating,正如來自原始實現(xiàn)的修改方法一樣。

下面的例子向Swift的Int類型添加了一個新的名為square的修改方法,來實現(xiàn)一個原始值的平方計算:

    extension Int {
        mutating func square() {
            self = self * self
        }
    }
    var someInt = 3
    someInt.square()
    // someInt 現(xiàn)在值是 9

下標(biāo)(Subscripts)

擴(kuò)展可以向一個已有類型添加新下標(biāo)。這個例子向Swift內(nèi)建類型Int添加了一個整型下標(biāo)。該下標(biāo)[n]返回十進(jìn)制數(shù)字從右向左數(shù)的第n個數(shù)字

  • 123456789[0]返回9
  • 123456789[1]返回8

...等等

    extension Int {
        subscript(var digitIndex: Int) -> Int {
            var decimalBase = 1
                while digitIndex > 0 {
                    decimalBase *= 10
                    --digitIndex
                }
                return (self / decimalBase) % 10
        }
    }
    746381295[0]
    // returns 5
    746381295[1]
    // returns 9
    746381295[2]
    // returns 2
    746381295[8]
    // returns 7

如果該Int值沒有足夠的位數(shù),即下標(biāo)越界,那么上述實現(xiàn)的下標(biāo)會返回0,因為它會在數(shù)字左邊自動補(bǔ)0:

    746381295[9]
    //returns 0, 即等同于:
    0746381295[9]

嵌套類型(Nested Types)

擴(kuò)展可以向已有的類、結(jié)構(gòu)體和枚舉添加新的嵌套類型:

    extension Character {
        enum Kind {
            case Vowel, Consonant, Other
        }
        var kind: Kind {
            switch String(self).lowercaseString {
            case "a", "e", "i", "o", "u":
                return .Vowel
            case "b", "c", "d", "f", "g", "h", "j", "k", "l", "m",
                 "n", "p", "q", "r", "s", "t", "v", "w", "x", "y", "z":
                return .Consonant
            default:
                return .Other
            }
        }
    }

該例子向Character添加了新的嵌套枚舉。這個名為Kind的枚舉表示特定字符的類型。具體來說,就是表示一個標(biāo)準(zhǔn)的拉丁腳本中的字符是元音還是輔音(不考慮口語和地方變種),或者是其它類型。

這個例子還向Character添加了一個新的計算實例屬性,即kind,用來返回合適的Kind枚舉成員。

現(xiàn)在,這個嵌套枚舉可以和一個Character值聯(lián)合使用了:

    func printLetterKinds(word: String) {
        println("'\(word)' is made up of the following kinds of letters:")
        for character in word {
            switch character.kind {
            case .Vowel:
                print("vowel ")
            case .Consonant:
                print("consonant ")
            case .Other:
                print("other ")
            }
        }
        print("\n")
    }
    printLetterKinds("Hello")
    // 'Hello' is made up of the following kinds of letters:
    // consonant vowel consonant consonant vowel

函數(shù)printLetterKinds的輸入是一個String值并對其字符進(jìn)行迭代。在每次迭代過程中,考慮當(dāng)前字符的kind計算屬性,并打印出合適的類別描述。所以printLetterKinds就可以用來打印一個完整單詞中所有字母的類型,正如上述單詞"hello"所展示的。

注意:
由于已知character.kindCharacter.Kind型,所以Character.Kind中的所有成員值都可以使用switch語句里的形式簡寫,比如使用 .Vowel代替Character.Kind.Vowel