亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb

首頁 > 編程 > Swift > 正文

Swift對比Kotlin之接口淺析

2024-07-21 23:03:36
字體:
供稿:網(wǎng)友

Kotlin 語言和 Swift 語言在一個團隊一起開發(fā)已經(jīng)很久了,由于平臺的差異性,他們經(jīng)常會進行一些技術(shù)上的交流(PK),「Kotlin vs. Swift」 系列就是他們在互相切磋時的語錄。內(nèi)容會由簡及深,慢慢深入。

技術(shù)漫談

Swift:

Hi, Kotlin 君, Swift 4 發(fā)布了,我們今天就基于 Swift 4 的新語法來討論一下接口吧?

Kotlin:

好啊,接口對我們開發(fā)來說是個很重要的概念。設計模式中要求我們寫代碼要遵循依賴倒置原則,就是程序要依賴于抽象接口,不要依賴于具體實現(xiàn),也就是要求我們要面向接口編程。

Swift:

是的,在 Swift 中,接口被稱為協(xié)議(即 Protocol ), 蘋果大大強化了 Protocol 在這門語言中的地位,整個 Swift 標準庫也是基于 Protocol 來設計的,可以說 Swift 是一門面向 protocol 編程的語言。

Kotlin:

聽起來好流比,那來說說你們是怎么定義接口的?

Swift:

我們用 Protocol 關鍵字來定義接口:

protocol SomeProtocol {

func f()

}

你們呢?

Kotlin:

我們同 Java 一樣,用 interface 關鍵字來定義接口:

interface MyInterface {

fun f()

}

Swift:

嗯,看起來就是關鍵字不一樣。你們怎么實現(xiàn)接口呢?

Kotlin:

一個類要實現(xiàn)某個接口,需要在類型名稱后加上協(xié)議名稱,中間以冒號(:)分隔:

class MyClass: MyInterface {

override fun f() {

// 具體實現(xiàn)

}

}

一個類或者對象可以實現(xiàn)一個或多個接口。實現(xiàn)多個接口時,各接口之間用逗號(,)分隔.

Swift:

我們也是一樣的,只是我們不需要寫 override 關鍵字,只有當子類復寫父類的方法或計算屬性時才需要用 override 修飾。另外,我們還可以通過擴展類型來實現(xiàn)協(xié)議:

class MyClass {

//...類的定義

}

extension MyClass: SomeProtocol {

func f() {

// 具體實現(xiàn)

}

}

Kotlin:

這意味著你們不用修改原有類型,就可以讓原有類型符合某個協(xié)議了,甚至可以擴展標準庫中的某個基礎類型來實現(xiàn)自定義的協(xié)議。這很符合開閉原則嘛。

Swift:

是啊,牛不牛 。

我們實現(xiàn)協(xié)議的類型除了 class 外,還可以是 struct 或 enum。

Kotlin:

Kotlin 沒有結(jié)構(gòu)體的概念, enum 也可以實現(xiàn)接口。

來說說你們的接口中可以聲明哪些東西吧?

Swift:

我們可以在協(xié)議中聲明屬性和方法,用 var 關鍵字來聲明變量屬性,并在屬性聲明后加上 { set get } 來表示屬性是可讀可寫的,用 { get } 來表示屬性是只讀的。

協(xié)議里面聲明的屬性和方法一定是抽象的,不能有實現(xiàn),由符合協(xié)議的類型來提供所有屬性和方法的實現(xiàn)。

Kotlin:

我們也可以聲明屬性和方法,而且 Kotlin 可以直接在接口中為屬性和方法提供默認實現(xiàn):

interface MyInterface {

val prop: Int // 抽象的

val propertyWithImplementation: String

get() = "foo"

fun foo() {

print(prop)

}

}

class MyClass : MyInterface {

override val prop: Int = 29

}

Swift:

雖然我們不能在協(xié)議中直接提供屬性和方法的默認實現(xiàn),但是我們可以通過協(xié)議擴展來達到此目的。

protocol MyProtocol {

var prop: Int { get set }

var propertyWithImplementation: String { get }

func foo()

}

extension MyProtocol {

var propertyWithImplementation: String {

return "foo"

}

func foo() {

print(prop)

}

}

class MyClass: MyProtocol {

var prop: Int = 29

}

Kotlin:

哇~,你們這個協(xié)議擴展有點厲害了。

Swift:

是的,正是這個特性,才使得我們面向協(xié)議編程成為可能。我們甚至可以在擴展中添加協(xié)議里沒有定義過的方法和屬性。

extension MyProtocol {

func isExceed() -> Bool {

return prop > 30

}

}

let instance = MyClass()

print(instance.isExceed())

// false

Kotlin:

這就意味著你們也有能力擴展標準庫里的協(xié)議了,可以很方便的給標準庫里的協(xié)議添加新的方法和屬性。

Swift:

聰明,確實是這樣。不僅如此,在擴展協(xié)議的時候,還可以指定一些限制條件,只有遵循協(xié)議的類型滿足這些限制條件時,才能獲得協(xié)議擴展提供的默認實現(xiàn)。

protocol TextRepresentable {

var textualDeion: String { get }

}

struct Hamster: TextRepresentable {

var name: String

var textualDeion: String {

return "A hamster named (name)"

}

}

extension Collection where Iterator.Element: TextRepresentable {

var textualDeion: String {

let itemsAsText = self.map { $0.textualDeion }

return "[" + itemsAsText.joined(separator: ", ") + "]"

}

}

let hamsters = [Hamster(name: "Jim"), Hamster(name: "Merry")]

print(hamsters.textualDeion)

// [A hamster named Jim, A hamster named Merry]

這里擴展了 Swift 標準庫中的 Collection 協(xié)議,但是限制只適用于集合中的元素遵循了 TextRepresentable 協(xié)議的情況。 因為 Swift 中 Array 符合 Collection 協(xié)議,而 Hamster 類型又符合 TextRepresentable 協(xié)議,所以 hamsters 可以使用 textualDeion 屬性得到數(shù)組內(nèi)容的文本表示。

Kotlin:

贊啊~,你們這個協(xié)議擴展太強大了,不僅可以擴展自己定義的協(xié)議,還可以擴展標準庫中的協(xié)議,怪不得蘋果稱 Swift 是面向協(xié)議編程的語言。

Swift 在實現(xiàn)多個協(xié)議時,會不會有不同協(xié)議帶來同名方法或?qū)傩缘臎_突的問題?

Swift:

我們還不能很好地處理多個協(xié)議的沖突問題。

Kotlin:

Kotlin 可以,Kotlin 有一套規(guī)則來處理這樣的沖突。在 Kotlin 中,如果一個類從它的直接超類繼承相同成員的多個實現(xiàn)(由于接口函數(shù)可以有實現(xiàn)),它必須覆蓋這個成員并提供其自己的實現(xiàn)。 為了表示采用從哪個超類型繼承的實現(xiàn),我們使用由尖括號中超類型名限定的 super,如 super。

open class A {

open fun f() { print("A") }

fun a() { print("a") }

}

interface B {

fun f() { print("B") } // interface members are 'open' by default

fun b() { print("b") }

}

class C() : A(), B {

// The compiler requires f() to be overridden:

override fun f() {

super.f() // call to A.f()

.f() // call to B.f()

super

}

}

Swift:

這個好贊,可以不怕名字沖突了 。

Kotlin 的接口中可以聲明類方法嗎?

Kotlin:

Kotlin 里面已經(jīng)沒有類方法的概念了。

Swift:

我們可以在協(xié)議中使用 static 關鍵字來聲明類型方法,如果實現(xiàn)該協(xié)議的類型是 class 類型,則在實現(xiàn)類中除了用 static 來修飾類型方法外,也可以使用 class關鍵字.

protocol SomeProtocol {

static func someTypeMethod()

}

class SomeClass: SomeProtocol {

// 這里也可以用 static 修飾,區(qū)別是 static 修飾的屬性

// 或方法不能被子類復寫,class 修飾的可以被子類復寫

class func someTypeMethod() {

print("type method")

}

}

Kotlin:

我們的接口雖然不支持類方法,但是我們可以給接口中定義的方法的參數(shù)設置默認值。

Swift:

這。。。我們不支持為協(xié)議中的方法的參數(shù)提供默認值。

Kotlin:

方法參數(shù)的默認值必須定義在接口中,在實現(xiàn)類或?qū)ο髮崿F(xiàn)該方法時,不能為函數(shù)提供默認值。同時接口的中函數(shù)不能用 JVMOverride 注解修飾,所以接口中定義的帶有默認值的參數(shù),不能為 Java 生成重載方法,如果接口是定義在庫里面,Kotlin 的實現(xiàn)也無法使用自動重載功能,需要手動重載。

interface IDownload{

fun(url: String, isSupportBreakpointC: Boolean = true)

}

class DownloadImpl: IDownload{

override fun(url: String, isSupportBreakpointC: Boolean){

}

}

Swift:

這點算你強。

我們的協(xié)議中可以定義可變方法,如果協(xié)議中定義的實例方法會改變遵循該協(xié)議的類型的實例,那么需要在該方法前加 mutating 關鍵字, 表示可以在該方法中修改它所屬的實例以及實例的任意屬性的值, 例如:

protocol Togglable {

mutating func toggle()

}

enum OnOffSwitch: Togglable {

case off, on

mutating func toggle() {

switch self {

case .off:

self = .on

case .on:

self = .off

}

}

}

var lightSwitch = OnOffSwitch.off

lightSwitch.toggle()

// lightSwitch 現(xiàn)在的值為 .On

Kotlin:

我們沒這特性,這點你贏了。

Swift:

豈止如此,我們的協(xié)議中還可以要求遵循協(xié)議的類型實現(xiàn)指定的構(gòu)造器:

protocol SomeProtocol {

init(someParameter: Int)

}

class SomeClass: SomeProtocol {

required init(someParameter: Int) {

// initializer implementation goes here

}

}

在符合協(xié)議的類中實現(xiàn)構(gòu)造器,必須在構(gòu)造器實現(xiàn)前加上 required 修飾符。使用 required 修飾符可以確保所有子類也必須提供此構(gòu)造器實現(xiàn),從而也能符合協(xié)議。 如果類已經(jīng)被標記為 final,那么不需要在協(xié)議構(gòu)造器的實現(xiàn)中使用 required 修飾符,因為 final 類不能有子類.

協(xié)議還可以為遵循協(xié)議的類型定義可失敗構(gòu)造器。

Kotlin:

好吧,我們不可以在接口中聲明構(gòu)造器。

Swift:

你們的接口可以繼承嗎?

Swift 中協(xié)議能夠繼承一個或多個其他協(xié)議,可以在繼承的協(xié)議的基礎上增加新的要求.

Kotlin:

當然可以,這是基本的用法好伐。

Swift:

好吧。。我們還可以通過讓協(xié)議繼承 AnyObject 協(xié)議來限制協(xié)議只能被 Class 類型遵循,而結(jié)構(gòu)體或枚舉不能遵循該協(xié)議。

Kotlin:

我們并沒有這種限制,接口可以被類和枚舉實現(xiàn)。

Swift:

你們的接口可以組合嗎?

Swift 可以采用 & 符號將多個協(xié)議進行組合:

protocol Named {

var name: String { get }

}

protocol Aged {

var age: Int { get }

}

struct Person: Named, Aged {

var name: String

var age: Int

}

func wishHappyBirthday(to celebrator: Named & Aged) {

print("Happy birthday, (celebrator.name), you're (celebrator.age)!")

}

let birthdayPerson = Person(name: "Malcolm", age: 21)

wishHappyBirthday(to: birthdayPerson)

// Prints "Happy birthday, Malcolm, you're 21!"

這里 wishHappyBirthday(to:) 函數(shù)的參數(shù)類型為 Named & Aged, 這意味著它不關心參數(shù)的具體類型,只要參數(shù)符合這兩個協(xié)議即可。當然也可以給組合的協(xié)議指定一個別名:typealias Property = Named & Aged

Kotlin:

666,你們的協(xié)議真是玩出花了,這個功能我們也沒有??。

Swift:

除了協(xié)議與協(xié)議組合外,協(xié)議還可以與類進行組合:

class Location {

var latitude: Double

var longitude: Double

init(latitude: Double, longitude: Double) {

self.latitude = latitude

self.longitude = longitude

}

}

class City: Location, Named {

var name: String

init(name: String, latitude: Double, longitude: Double) {

self.name = name

super.init(latitude: latitude, longitude: longitude)

}

}

func beginConcert(in location: Location & Named) {

print("Hello, (location.name)!")

}

let seattle = City(name: "Seattle", latitude: 47.6, longitude: -122.3)

beginConcert(in: seattle)

這里的 beginConcert(in:) 函數(shù)的參數(shù)要求是 Location 的子類,且必須符合 Named 協(xié)議.

Kotlin:

太贊了~,給你點32個贊!

Swift:

你們是怎么判斷某個實例是否符合某個協(xié)議的?

Kotlin:

這就是判斷某個對象是否是某個類型嘛,當然是用 is 啦,如果是類型轉(zhuǎn)換的話用 as 。

Swift:

嗯嗯,這點我們是一致的。

你們可以定義接口中的方法或?qū)傩詾榭蛇x嗎?

Kotlin:

何謂可選?

Swift:

就是可以實現(xiàn)也可以不實現(xiàn)

Kotlin:

前面講過了啊,如果接口中的屬性或方法在實現(xiàn)類中可以實現(xiàn)也可以不實現(xiàn),則可以在接口定義中為該方法提供默認實現(xiàn)。

Swift:

嗯,Swift 是通過協(xié)議擴展提供默認實現(xiàn)來到達可選的目的。

不過 Swift 也可以像 Objective-C 里那樣定義可選的接口方法,就需要在 protocol 定義之前加上 @objc,將 protocol 變?yōu)?Objective-C 的。然后使用 optional 關鍵字來聲明某些方法或?qū)傩栽诜显搮f(xié)議的類中可以不實現(xiàn),如下:

@objc protocol CounterDataSource {

@objc optional func incrementForCount(count: Int) -> Int

@objc optional var fixedIncrement: Int { get }

}

需要注意的是,標記為 @objc 的 protocol 只能被 class 實現(xiàn),不能被 struct 和 enum 類型實現(xiàn),而且實現(xiàn)它的 class 中的方法也必須被標注為 @objc,或者整個類就是繼承自 NSObject。

Kotlin:

額。。。這豈不是很蛋疼

Swift:

是的,所以這種方式并不提倡。

Swift 可以使用 Protocol 來實現(xiàn)委托(代理)模式,委托(代理)模式允許類或結(jié)構(gòu)體將一些需要它們負責的功能委托給其他類型的實例,如下:

protocol RentHouserDelegate{

func rent(_ name:String);

}

class Tenant {

var name = "lucy"

var delegate: RentHouserDelegate?

func rentHouse(){

delegate?.rent(name)

}

}

class Intermediary: RentHouserDelegate {

var name="lily"

func rent(_ name:String) {

print("(name) 請 (self.name) 幫她租一套房子");

}

}

var person = Tenant();

person.delegate = Intermediary()

person.rentHouse()

// lucy 請 lily 幫她租一套房子

Kotlin:

這是接口的一種常用方法,我們依賴注入框架就大量使用這種方式。

Swift:

哈哈,英雄所見略同。

好了,就到這吧,今天的PK互有攻防,好帶勁??~

Kotlin:

總體來說還是你們的協(xié)議比較強大。

Swift:

那是,要不然蘋果怎么敢稱 Swift 是一門面向協(xié)議編程的語言呢

Kotlin:

好吧,咱們來日方長。

Swift:

嗯嗯,后會有期。

知識點總結(jié)

Kotlin

接口定義

同 Java 一樣,Kotlin 用 interface 關鍵字來定義接口,Kotlin 接口中可以有函數(shù)的實現(xiàn),也可以只有抽象方法,接口無法保存狀態(tài),它可以有屬性但必須聲明為抽象或提供訪問器實現(xiàn)。

interface MyInterface {

fun bar()

fun foo() {

// 可選的方法體

}

}

實現(xiàn)接口

Kotlin 的一個類或者對象可以實現(xiàn)一個或多個接口。由于 Kotlin 接口本身的函數(shù)式可以有實現(xiàn)的,所以在一個類或?qū)ο髮崿F(xiàn)多個接口的時候,就有可能發(fā)生沖突,這包括接口之間的的成員沖突,也包括接口與父類直接的成員沖突。

覆蓋沖突

在 Kotlin 中,如果一個類從它的直接超類繼承相同成員的多個實現(xiàn)(由于接口函數(shù)可以有實現(xiàn)),它必須覆蓋這個成員并提供其自己的實現(xiàn)。 為了表示采用從哪個超類型繼承的實現(xiàn),我們使用由尖括號中超類型名限定的 super,如 super

。

open class A {

open fun f() { print("A") }

fun a() { print("a") }

}

interface B {

fun f() { print("B") } // interface members are 'open' by default

fun b() { print("b") }

}

class C() : A(), B {

// The compiler requires f() to be overridden:

override fun f() {

super.f() // call to A.f()

 

super.f() // call to B.f()

}

}

同時繼承 A 和 B 沒問題,并且 a() 和 b() 也沒問題因為 C 只繼承了每個函數(shù)的一個實現(xiàn)。 但是 f() 由 C 繼承了兩個實現(xiàn),所以我們必須在 C 中覆蓋 f() 并且提供我們自己的實現(xiàn)來消除歧義。

接口中的屬性

Kotlin 中可以在接口中定義屬性。在接口中聲明的屬性要么是抽象的,要么提供訪問器的實現(xiàn)。在接口中聲明的屬性不能有幕后字段(backing field),因此接口中聲明的訪問器不能引用它們。

interface MyInterface {

val prop: Int // 抽象的

val propertyWithImplementation: String

get() = "foo"

fun foo() {

print(prop)

}

}

class Child : MyInterface {

override val prop: Int = 29

}

函數(shù)默認參數(shù)與重載

如果接口函數(shù)需要定義默認值的話,必須定義在接口中,在實現(xiàn)類或?qū)ο髮崿F(xiàn)該方法時,不能為函數(shù)提供默認值。同時接口的中函數(shù)不能用 JVMOverride 注解修飾,所以接口中定義的帶有默認值的參數(shù),不能為 Java 生成重載方法,如果接口是定義在庫里面,Kotlin 的實現(xiàn)也無法使用自動重載功能,需要手動重載。

interface IDownload{

fun(url: String, isSupportBreakpointC: Boolean = true)

}

class DownloadImpl{

override fun(url: String, isSupportBreakpointC: Boolean){

}

}

Swift

Protocol

Swift 是一門支持面向協(xié)議編程的語言,在 Swift 語言中,協(xié)議被賦予了更多的功能和更廣闊的使用空間。恰逢蘋果發(fā)布了 swift 4,以下都是基于最新的 swift 4 語法進行講述。

協(xié)議語法

協(xié)議聲明:

protocol SomeProtocol {

// protocol definition goes here

}

要讓自定義類型符合某個協(xié)議,需要在類型名稱后加上協(xié)議名稱,中間以冒號(:)分隔。符合多個協(xié)議時,各協(xié)議之間用逗號(,)分隔. swift 中,符合協(xié)議的類型可以是 class、struct 或 enum。

struct SomeStructure: FirstProtocol, AnotherProtocol {

// structure definition goes here

}

需要注意的是,如果某個類在符合某個協(xié)議的同時又繼承自某個父類,應將其父類名放在其符合的協(xié)議名之前。

協(xié)議屬性聲明

協(xié)議中可以聲明符合此協(xié)議的類型必須實現(xiàn)的屬性:

protocol SomeProtocol {

var mustBeSettable: Int { get set }

var doesNotNeedToBeSettable: Int { get }

}

協(xié)議不指定屬性是存儲型屬性還是計算型屬性,它只指定屬性的名稱和類型,以及屬性是可讀的還是可讀可寫的。

協(xié)議總是用 var 關鍵字來聲明變量屬性,在類型聲明后加上 { set get } 來表示屬性是可讀可寫的,用 { get } 來表示屬性是只讀的。

協(xié)議中總是使用 static 關鍵字定義類型屬性,如果是 class類型實現(xiàn)協(xié)議,除了 static,還可以使用 class 關鍵字來聲明類型屬性。

protocol AnotherProtocol {

static var someTypeProperty: Int { get }

}

class SomeClass: AnotherProtocol {

// 這里也可以用 static 修飾,區(qū)別是 static 修飾的屬性

或方法不能被子類復寫,class 修飾的可以被子類復寫

class var someTypeProperty: Int {

return 0

}

}

協(xié)議方法聲明

協(xié)議可以要求遵循協(xié)議的類型實現(xiàn)某些指定的實例方法或類方法。需要注意的是,不支持為協(xié)議中的方法的參數(shù)提供默認值。

protocol RandomNumberGenerator {

func random() -> Double

}

與屬性類似,在協(xié)議中也使用 static 定義類方法,當 class 類型實現(xiàn)協(xié)議時,可以使用 class 關鍵字來修飾.

如果協(xié)議中定義的實例方法會改變遵循該協(xié)議的類型的實例,那么需要在該方法前加 mutating 關鍵字, 表示可以在該方法中修改它所屬的實例以及實例的任意屬性的值, 例如:

protocol Togglable {

mutating func toggle()

}

enum OnOffSwitch: Togglable {

case off, on

mutating func toggle() {

switch self {

case .off:

self = .on

case .on:

self = .off

}

}

}

var lightSwitch = OnOffSwitch.off

lightSwitch.toggle()

// lightSwitch 現(xiàn)在的值為 .On

協(xié)議構(gòu)造器聲明

協(xié)議可以要求遵循協(xié)議的類型實現(xiàn)指定的構(gòu)造器:

protocol SomeProtocol {

init(someParameter: Int)

}

class SomeClass: SomeProtocol {

required init(someParameter: Int) {

// initializer implementation goes here

}

}

在符合協(xié)議的類中實現(xiàn)構(gòu)造器,必須在構(gòu)造器實現(xiàn)前加上 required 修飾符。使用 required 修飾符可以確保所有子類也必須提供此構(gòu)造器實現(xiàn),從而也能符合協(xié)議. 如果類已經(jīng)被標記為 final,那么不需要在協(xié)議構(gòu)造器的實現(xiàn)中使用 required 修飾符,因為 final 類不能有子類.

協(xié)議還可以為遵循協(xié)議的類型定義可失敗構(gòu)造器。

委托(代理)模式

Swift 可以使用 Protocol 來實現(xiàn)委托(代理)模式,委托(代理)模式允許類或結(jié)構(gòu)體將一些需要它們負責的功能委托給其他類型的實例,如下:

protocol RentHouserDelegate{

func rent(_ name:String);

}

class Tenant {

var name = "lucy"

var delegate: RentHouserDelegate?

func rentHouse(){

delegate?.rent(name)

}

}

class Intermediary: RentHouserDelegate {

var name="lily"

func rent(_ name:String) {

print("(name) 請 (self.name) 幫她租一套房子");

}

}

var person = Tenant();

person.delegate = Intermediary()

person.rentHouse()

// lucy 請 lily 幫她租一套房子

通過擴展遵循協(xié)議

可以通過擴展令已有類型遵循并符合協(xié)議:

protocol TextRepresentable {

var textualDeion: String { get }

}

struct Circular {

var radius: Int

}

extension Circular: TextRepresentable {

var textualDeion: String {

return "The circular's radius is (radius)"

}

}

let circular = Circular(radius: 2)

print(circular.textualDeion)

// The circular's radius is 2

當一個類型已經(jīng)符合了某個協(xié)議中的所有要求,卻還沒有聲明遵循該協(xié)議時,可以通過空擴展來使該類型遵循該協(xié)議:

struct Square {

var width: Int

var textualDeion: String {

return "The square's width is (width)"

}

}

extension Square: TextRepresentable {}

let square = Square(width: 3)

let squareTextRepresentable: TextRepresentable = square

print(squareTextRepresentable.textualDeion)

// The square's width is 3

協(xié)議類型

盡管協(xié)議本身并未實現(xiàn)任何功能,但是協(xié)議可以被當做一個成熟的類型來使用。協(xié)議類型也可以在數(shù)組或者字典這樣的集合中使用:

let things: [TextRepresentable] = [circular, square]

for thing in things {

print(thing.textualDeion)

}

協(xié)議的繼承

協(xié)議能夠繼承一個或多個其他協(xié)議,可以在繼承的協(xié)議的基礎上增加新的要求:

protocol PrettyTextRepresentable: TextRepresentable {

var prettyTextualDeion: String { get }

}

extension Square: PrettyTextRepresentable {

var prettyTextualDeion: String {

var output = textualDeion + ": "

output += "the area is (width*width)"

return output

}

}

print(square.prettyTextualDeion)

// The square's width is 3: the area is 9

Class 類型專屬協(xié)議

通過讓協(xié)議繼承 AnyObject 協(xié)議來限制協(xié)議只能被 Class 類型遵循,而結(jié)構(gòu)體或枚舉不能遵循該協(xié)議

protocol SomeClassOnlyProtocol: AnyObject, SomeInheritedProtocol {

// class-only protocol definition goes here

}

協(xié)議合成

可以采用 & 符號將多個協(xié)議進行組合:

protocol Named {

var name: String { get }

}

protocol Aged {

var age: Int { get }

}

struct Person: Named, Aged {

var name: String

var age: Int

}

func wishHappyBirthday(to celebrator: Named & Aged) {

print("Happy birthday, (celebrator.name), you're (celebrator.age)!")

}

let birthdayPerson = Person(name: "Malcolm", age: 21)

wishHappyBirthday(to: birthdayPerson)

// Prints "Happy birthday, Malcolm, you're 21!"

這里 wishHappyBirthday(to:) 函數(shù)的參數(shù)類型為 Named & Aged, 這意味著它不關心參數(shù)的具體類型,只要參數(shù)符合這兩個協(xié)議即可。當然也可以給組合的協(xié)議指定一個別名:typealias Property = Named & Aged

除了協(xié)議與協(xié)議組合外,協(xié)議還可以與 class 進行組合:

class Location {

var latitude: Double

var longitude: Double

init(latitude: Double, longitude: Double) {

self.latitude = latitude

self.longitude = longitude

}

}

class City: Location, Named {

var name: String

init(name: String, latitude: Double, longitude: Double) {

self.name = name

super.init(latitude: latitude, longitude: longitude)

}

}

func beginConcert(in location: Location & Named) {

print("Hello, (location.name)!")

}

let seattle = City(name: "Seattle", latitude: 47.6, longitude: -122.3)

beginConcert(in: seattle)

這里的 beginConcert(in:) 函數(shù)的參數(shù)要求是 Location 的子類,且必須符合 Named 協(xié)議.

檢查協(xié)議一致性

可以通過 is as? as 來檢查某個實例是否符合某個協(xié)議:

let things: [Any] = [circular, square, "abc"]

for thing in things {

if let object = thing as? TextRepresentable {

print(object.textualDeion)

} else {

print("It does not conform to TextRepresentable")

}

}

可選協(xié)議

原生的 Swift protocol 里沒有可選項,所有定義的方法都是必須實現(xiàn)的。如果想要像 Objective-C 里那樣定義可選的接口方法,就需要在 protocol 定義之前加上 @objc,將 protocol 變?yōu)?Objective-C 的。然后使用 optional 關鍵字來聲明某些方法或?qū)傩栽诜显搮f(xié)議的類中可以不實現(xiàn),如下:

@objc protocol CounterDataSource {

@objc optional func incrementForCount(count: Int) -> Int

@objc optional var fixedIncrement: Int { get }

}

需要注意的是,標記為 @objc 的 protocol 只能被 class 實現(xiàn),不能被 struct 和 enum 類型實現(xiàn),而且實現(xiàn)它的 class 中的方法還必須也被標注為 @objc,或者整個類就是繼承自 NSObject。這還是很蛋疼的。

協(xié)議擴展

協(xié)議可以通過擴展來為遵循協(xié)議的類型提供屬性和方法的實現(xiàn),即使協(xié)議中沒有聲明。這樣就無需在每個遵循協(xié)議的類型中都重復同樣的實現(xiàn),也無需使用全局函數(shù)。

protocol TextRepresentable {

var textualDeion: String { get }

}

extension TextRepresentable {

func hasDeion() -> Bool {

return !textualDeion.isEmpty

}

}

還可以通過協(xié)議擴展來為協(xié)議要求的屬性、方法提供默認的實現(xiàn)。這樣在遵循這個協(xié)議的類型中,可以不用實現(xiàn)這個屬性或方法,調(diào)用的時候默認調(diào) extension 中的實現(xiàn)。這也相當于變相將 protocol 中的屬性或方法設定為了 `optional.

extension TextRepresentable {

var textualDeion: String {

return "This is a shape"

}

}

在擴展協(xié)議的時候,也可以指定一些限制條件,只有遵循協(xié)議的類型滿足這些限制條件時,才能獲得協(xié)議擴展提供的默認實現(xiàn)。

extension Collection where Iterator.Element: TextRepresentable {

var textualDeion: String {

let itemsAsText = self.map { $0.textualDeion }

return "[" + itemsAsText.joined(separator: ", ") + "]"

}

}

let circulars = [Circular(radius: 1), Circular(radius: 2)]

print(circulars.textualDeion)

// [The circular's radius is 1, The circular's radius is 2]

這里擴展了 Collection 協(xié)議,但是限制只適用于集合中的元素遵循了 TextRepresentable 協(xié)議的情況。 因為 Swift 中 Array 符合 Collection 協(xié)議,而 Circular 類型又符合 TextRepresentable 協(xié)議,所以 circulars 可以使用 textualDeion 屬性得到數(shù)組內(nèi)容的文本表示

文章轉(zhuǎn)載自網(wǎng)絡


注:相關教程知識閱讀請移步到kotlin教程頻道。
發(fā)表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發(fā)表
亚洲第一视频网| 在线观看三级视频欧美| 777国产偷窥盗摄精品视频| 亚洲精品人成网在线播放影院| 久久久久久久久成人| 美女网站在线看| 97caopor国产在线视频| 国产精品免费一区二区| 日韩精品无码一区二区三区久久久| 中文字幕69页| 日韩暖暖在线视频| 蜜桃视频在线播放| 国产欧美精品aaaaaa片| 国产aⅴ精品一区二区三区黄| 亚洲欧美日韩一区在线| 欧美专区在线视频| 欧美黑人性生活视频| 黄a在线观看| 深田えいみ中文字幕99久久| 久久久久久网址| 杨钰莹一级淫片aaaaaa播放| 国产乱码77777777| 国产成人久久精品一区二区三区| 91理论片午午论夜理片久久| 99久久婷婷国产精品综合| 国产黄a三级三级三级| 一级片免费在线| 欧美韩一区二区| 免费无码av片在线观看| 香蕉精品视频在线观看| 日韩一二三四区| 大地资源网在线观看免费官网| 欧美性20hd另类| 青春草视频在线| www.玖玖玖| 久久一区二区三区超碰国产精品| 亚洲国产欧美国产综合一区| 成人午夜淫片100集| 国产欧美日韩精品专区| 国产短剧电视剧免费观看| 成人av免费观看| 成人做爰高清视频网站| 亚洲一区二区三区高清视频| 亚洲色图偷拍自拍| 伊人精品综合| 中文乱码字幕高清在线观看| 亚洲天堂视频网| www亚洲精品| 精品成人av一区二区在线播放| 中文字幕欧美日韩一区二区三区| 中文字幕日本在线观看| 91视频88av| 99热这里只有精品7| 国产高清视频在线| 日韩高清在线观看一区二区| 婷婷伊人五月天| 国产精品久久久久久久午夜片| aa免费在线观看| 超碰在线影院| 午夜精品一区二区三区免费视频| 成人欧美一区二区三区黑人一| 性感美女一区二区三区| 亚洲欧美日韩一区二区三区在线观看| 147欧美人体大胆444| 国产一区二区三区直播精品电影| 日韩精品xxxx| 成人免费毛片高清视频| 国产无精乱码一区二区三区| 日本免费精品视频| 亚洲做受高潮无遮挡| 91亚洲精品视频在线观看| 国产爆初菊在线观看免费视频网站| 欧美综合视频在线观看| 国产精品天干天干在观线| 久久精品99国产精品日本| 欧美一激情一区二区三区| 国产一二三四在线| 狠狠干狠狠操视频| 精品无码黑人又粗又大又长| www.日本久久| 久久久精品美女| 青青草免费在线视频观看| 强伦女教师2:伦理在线观看| 亚洲一区二区乱码| 91福利在线观看视频| 91在线最新| 91精品尤物| 免费电影网站在线观看| 免费av网站在线看| 免费成人深夜夜行p站| 91成人小视频| 欧美亚洲日本网站| 男人艹女人在线观看| 99热这里只有精| 欧美成人精品影院| 成人国产亚洲精品a区天堂华泰| 日韩精品最新网址| 国产69精品久久久久久久久久| 日本精品一二三区| 成人性生交大片免费看中文视频| 久久久久国色av免费看影院| 久草视频在线播放| 1024国产在线| 欧美大片一区二区三区| 色偷偷亚洲第一成人综合网址| 亚洲不卡一区二区三区| 一级网站在线观看| 91在线观看| 亚洲精品一区二三区不卡| 久草在线成人| 亚洲色图一二三区| jvid一区二区三区| 疯狂欧美牲乱大交777| a级一a一级在线观看| 五月婷婷免费视频| 99精彩视频在线观看免费| 亚洲精品久久久久avwww潮水| 免费视频久久久| 国产小视频在线免费观看| 国产资源中文字幕| 全亚洲第一av番号网站| 欧美影院午夜播放| 国产精品亚洲精品| 97成人精品视频在线观看| 国产av一区二区三区传媒| 欧美一区二区三区久久综| 成人午夜av影视| 全部a∨一极品视觉盛宴| 噜噜噜久久,亚洲精品国产品| 国产精品自在自线| 国产精品99精品久久免费| 破处女黄色一级片| 337p粉嫩大胆噜噜噜噜噜91av| 国产精品theporn| 天天操天天干天天爱| 在线观看日本视频| 91高清视频在线观看| 色yeye免费人成网站在线观看| 亚洲乱码国产乱码精品精天堂| 999精品视频在线观看播放| 97久久超碰福利国产精品…| 欧美日韩国产成人在线91| 亚洲视频重口味| 欧美国产日韩在线视频| 欧美在线三级电影| 少妇视频在线观看| 亚洲丝袜在线观看| 亚洲精品美女91| 国产精品高潮呻吟AV无码| 国产精品久久久久久亚洲色| 亲爱的老师9免费观看全集电视剧| 成人欧美一区二区三区在线播放| 懂色av粉嫩av蜜臀av一区二区三区| 欧美色婷婷天堂网站| 欧美午夜女人视频在线| 国产中文字幕在线播放| 中文字幕在线视频网| 欧美亚洲一级| 久久久久狠狠高潮亚洲精品| 日韩激情美女| 国产精品久久久久一区二区国产| 亚洲日本成人| 欧美一级视频| 九色porn蝌蚪| 亚洲制服在线观看| 国产片在线播放| 成人av一区二区三区在线观看| 精品一区二区在线观看| 亚洲精品久久久久久下一站| 欧美在线观看一二区| 日韩欧美视频一区二区| 一级毛片aaaaaa免费看| 亚洲欧美国产高清va在线播| 日韩国产成人无码av毛片| 在线日韩中文字幕| 香蕉av一区二区三区| 一区二区三区中文在线| 综合久久给合久久狠狠狠97色| 国产剧情在线视频| 黄色www网站| 蜜桃精品噜噜噜成人av| 国产精美视频| 亚洲AV无码片久久精品| 精品不卡在线视频| 日本三级视频网站| 成人免费av在线| 免费在线观看黄色| 欧美最猛性xxxxx免费| 亚洲午夜久久久久久久久久久| 国产精品沙发午睡系列990531| 天天综合日日夜夜精品| 韩国黄色一级大片| 国产美女www爽爽爽视频| 亚洲一区二区三区自拍| 国产精品7m视频| 在线看黄的网站| 日韩精品福利网| 亚洲国产美女久久久久| 亚洲欧美偷拍自拍| 一级在线观看| 激情网址大全| 影音先锋中文字幕第一页| 三妻四妾的电影电视剧在线观看| 国产亚洲综合色| 中文字幕免费高| 日韩视频一区二区三区在线播放| 在线免费一级片| 成人黄色网址在线观看| 国产又粗又硬又长又爽| 成人国产精品久久久久久亚洲| 特级西西444www高清大视频| 做爰无遮挡三级| 亚洲精品成人久久久998| 日本最黄一级片免费在线| 亚洲美女主播视频免费观看| 久久精品第一页| 亚洲h动漫在线| 踪合国产第二页| 九色.com| 国产精品无码久久久久久| 538国产精品一区二区免费视频| 2019亚洲男人天堂| 自拍偷拍欧美激情| 91麻豆产精品久久久久久| jvid福利写真一区二区三区| 国产午夜精品一区二区三区欧美| 欧美夫妇交换xxx| 欧美人成在线视频| 成人av番号网| 色94色欧美sute亚洲线路一久| 日韩美女视频一区| 樱空桃在线播放| www.成人69.com| 99久在线精品99re8热| 亚洲欧洲中文日韩久久av乱码| 久久成人综合| 欧美国产中文字幕| 91麻豆国产语对白在线观看| 另类ts人妖一区二区三区| 欧美日韩国产中文精品字幕自在自线| 韩国三级与黑人| 黄色av免费播放| 日韩精品国内| 久久精品国产**网站演员| 一区二区三区性视频| 精精国产xxxx视频在线| 国产精品一级视频| 97夜夜澡人人双人人人喊| 国产破处视频在线观看| 国产伦精品一区二区三区视频我| 丰满熟妇人妻中文字幕| 色妞欧美日韩在线| 午夜精产品一区二区在线观看的| 成人免费淫片| 色在线免费观看| 欧美 日韩 人妻 高清 中文| 精品无人乱码一区二区三区的优势| 欧美成人一区二区三区在线观看| 经典三级在线| 日韩视频1区| 免费的很黄很污的视频网站| 国产精品99蜜臀久久不卡二区| 香蒸焦蕉伊在线| 亚洲少妇最新在线视频| 大地资源二中文在线影视观看| 亚洲免费观看高清完整版在线| 天堂蜜桃一区二区三区| 风间由美一区二区三区| 日韩欧美国产激情| 五月开心播播网| www国产亚洲精品久久麻豆| 亚洲精品555| 同性gay免费| 91视频国产一区| 国产精品mm| 韩国精品在线观看| 日产午夜精品一线二线三线| 26uuu亚洲| 丰满湿润大白屁股bbw按摩| 国产一区私人高清影院| 亚洲中文字幕无码专区| 欧美亚洲日本一区| 国产 欧美 日韩 在线| 日韩欧美中文字幕一区| 婷婷综合激情| 97精品人妻一区二区三区蜜桃| 国产综合精品在线| 国产香蕉免费精品视频| 免费黄色片视频| jizzjizzjizzjizzjizzjizzjizz| 亚洲欧美偷拍另类a∨色屁股| 日本999视频| 美女的胸无遮挡在线观看| 日本黄色激情视频| 久久99精品久久久久久欧洲站| 永久免费观看片现看| 国产制服91一区二区三区制服| 在线国产中文字幕| 成人在线视频www| 国产91大片| 国产高清在线视频| 狠狠人妻久久久久久综合麻豆| 国产高清一级毛片在线不卡| 91久久国产自产拍夜夜嗨| 欧美aaa一级片| 一区二区三区四区欧美| 欧美一区二区三区网站| 亚洲欧美日韩国产| 99久久久无码国产精品| 免费观看日韩毛片| 国产精品视频一区二区三区| 日本午夜精品一区二区| 麻豆国产精品一区| 久久精品三级视频| 自拍偷拍亚洲综合| 你懂的视频在线免费| 亚洲日韩中文字幕在线播放| 久久美女免费视频| 欧美肉大捧一进一出免费视频| 国产精品视频九色porn| 欧美一级黄色影院| 最新视频 - x88av| 成人久久一区二区三区| 成年女人色毛片免费| 欧洲视频一区二区三区| 在线观看中文字幕视频| 搡老女人一区二区三区视频tv| 黄视频网站免费看|