閉包
javascript
首先來看一段示例:
php
//計算一個數的平方
//函數寫法func square(a : Int) -> Int { return a * a}square(a: 6)
//閉包寫法let sq = { (a : Int) -> Int in return a * a}sq(6)
閉包的寫法模式:
java
let 閉包名 = { 函數類型 in 須要執行的代碼塊}
閉包可以捕獲和存儲定義在其上下文中的任何常量和變量,即閉合幷包裹那些常量和變量,所以被稱爲「閉包」。nginx
閉包是能夠被傳遞和引用的一個獨立模塊。編程
閉包跟函數同樣,也是引用類型。
swift
閉包表達式
數組
閉包表達式的語法有以下的通常形式:ruby
{ (參數羅列) -> (返回值類型) in 須要執行的代碼語句}
說明以下:
微信
1,閉包表達式由一對花括號 {} 開始與結束閉包
2,由 in 關鍵字將閉包分割成兩部分:參數與返回值(能夠理解成函數的類型)與閉包體
3,閉包中的參數不一樣於函數中的參數的一點是,閉包中的參數不能提供默認值,而函數中的參數能夠提供默認值。其餘都是同樣的。
閉包的簡寫
首先咱們來看一個例子,從一個數組中篩選出合適的數據組成新的數組:
//首先定義一個函數,函數有兩個參數,第一個參數是須要篩選的數組,第二個參數是篩選條件函數func getNewList(scores : [Int], checkMethod : (Int)->Bool) -> [Int] { var newList = [Int]() for num in scores { if checkMethod(num) { newList.append(num) } } return newList}
//函數是一種特殊的閉包,因此上面的篩選條件函數能夠寫成以下閉包形式let newList = getNewList(scores: [55, 60, 71, 86, 98, 100], checkMethod: {(numInt : Int) -> Bool in return numInt > 80})print(newList) // [86, 98, 100]
let newList = getNewList(scores: [55, 60, 71, 86, 98, 100], checkMethod: {(numInt : Int) -> Bool in return numInt > 80})
上面的這行代碼,是閉包的完整寫法。下面來看一些簡寫的寫法。
第一層簡寫:省略掉閉包類型中的 -> 與 返回值類型 ,由於根據後面的表達式能夠推斷出返回值是一個Bool
let newList = getNewList(scores: [55, 60, 71, 86, 98, 100], checkMethod: {(numInt : Int) in return numInt > 80})
第二層簡寫:省略掉參數的類型和小括號,由於參數的類型能夠根據定義閉包時的函數類型進行推斷
let newList = getNewList(scores: [55, 60, 71, 86, 98, 100], checkMethod: {numInt in return numInt > 80})
第三層簡寫:省略掉 return 關鍵字,在單行閉包的時候,return關鍵字能夠省略
let newList = getNewList(scores: [55, 60, 71, 86, 98, 100], checkMethod: {numInt in numInt > 80})
第四層簡寫:省略掉參數的聲明和 in 關鍵字,使用參數名稱縮寫$0
let newList = getNewList(scores: [55, 60, 71, 86, 98, 100], checkMethod: {$0 > 80})
Swift 提供了參數名稱的縮寫功能,直接經過$0、$一、$2來順序調用閉包的參數
最多見的閉包類型——尾隨閉包
尾隨閉包是最多見的一種閉包類型。
尾隨閉包是一個在函數調用的時候,書寫在函數括號以後的閉包表達式。當函數中最後一個參數是閉包表達式的時候,在調用該函數的時候,就能夠將做爲最後一個參數的閉包表達式寫成尾隨閉包。
func getNewList(scores : [Int], checkMethod : (Int)->Bool) -> [Int] { var newScoreList = [Int]() for score in scores { if checkMethod(score) { newScoreList.append(score) } } return newScoreList}
//調用函數的時候,不使用尾隨閉包getNewList(scores: [41,62,83], checkMethod: { (score : Int) -> Bool in return score > 60})
//調用函數的時候,使用尾隨閉包getNewList(scores: [41, 62, 83]) { (score) -> Bool in return score > 60}
枚舉
枚舉的定義
在C和OC中,枚舉成員在被建立的時候會被賦予一個默認的整數值,枚舉的本質就是一組整型值。
而在Swift中,枚舉是更加靈活的,第一,你沒必要給每個枚舉成員提供一個值;第二,若是須要給枚舉成員提供值,那麼能夠提供的值類型包括字符、字符串、整型值、浮點值等。
定義方式一:
enum CompassPoint { case East case West case North case South}
這裏的 case 關鍵詞代表新的一行成員值將被定義。
與C/OC不一樣的一點是,Swift的枚舉成員在被建立的時候不會被賦予一個默認的整數值。好比上面的這個例子中,East、West、North和South不是隱式的等於0、一、二、3。
定義方式二:
enum CompassPoint { case East, West, North, South}
枚舉的多個成員值能夠出如今同一行上,此時只須要只用一個case 關鍵詞便可。
枚舉的賦值
枚舉類型賦值能夠是字符、字符串、整型、浮點型。
若是要給枚舉類型賦值,則必需要在枚舉類型後面明確說明值的具體類型:
enum CompassPoint : Int{ case East = 1 case West = 2 case North = 3 case South = 4}
enum CompassPoint : Double{ case East = 1.0 case West = 2.0 case North = 3.0 case South = 4.0}
enum CompassPoint : String{ case East = "East" case West = "West" case North = "North" case South = "South"}
枚舉的類型推斷
首先給變量賦一個枚舉值:
enum CompassPoint : String{ case East = "East" case West = "West" case North = "North" case South = "South"}
var a = CompassPoint.Eastprint(a) // East
而後對該變量進行窮舉:
switch a {case CompassPoint.East: print("東")case CompassPoint.West: print("西")case CompassPoint.North: print("北")case CompassPoint.South: print("南")}
上面的這個窮舉能夠簡寫爲以下(將枚舉類型移除):
switch a {case .East: print("東")case .West: print("西")case .North: print("北")case .South: print("南")}
之因此能夠將枚舉類型給簡化掉,是由於根據上下文,系統能夠檢測到變量a 匹配的值是 CompassPoint 這個枚舉類型下面的值。這就是Swift中的枚舉類型推斷。
枚舉的原始值
在C/OC中,枚舉的本質就是整數。因此C/OC的枚舉是有原始值的,而且默認是從0開始。
Swift中的枚舉是沒有原始值的,可是能夠在定義的時候告訴系統讓枚舉有原始值。
關於設置Swift中枚舉的原始值,須要注意如下幾點:
若是原始值是String類型,則原始值是區分大小寫的
經過 rawValue 能夠獲取原始值
經過 rawValue 返回的枚舉是一個可選型,由於原始值對應的枚舉值不必定存在
若是想指定第一個元素的原始值以後,後面的元素的原始值可以默認+1,則枚舉必定是Int類型。
enum CompassPoint : Int { case East = 1 case West case North case South}
let a = CompassPoint.Northprint(a) // Northprint(a.rawValue) // 3
這個例子中,枚舉的原始值設置的是Int類型,而且設置了第一個枚舉值的原始值是1,因此North的原始值就是3。
enum CompassPoint : Int { case East = 1 case West case North case South}
//經過原始值來獲取對應的枚舉值//這裏獲取的枚舉值是一個可選型,由於原始值對應的枚舉值不必定存在let b = CompassPoint(rawValue: 4)let c = CompassPoint(rawValue: 5)
結構體
結構體(struct)是由一系列具備相同類型或者不一樣類型的數據構成的數據集合。
結構體既能夠定義屬性(變量、常量),也能夠定義方法(函數)。
Swift中的結構體是值類型。
結構體的定義語法
struct 結構體名稱 { // 屬性和方法}
舉例以下:
struct Person { var name = "norman" var age = 18 var gentle = "man" func singASong() { print("《海闊天空》") }}
該例中,定義了一個名叫Person的結構體。這個結構體擁有三個屬性(name、age、gentle)和一個方法(singASong)。
結構體實例
實例化結構體的方式一:
實例化結構體最簡單的方式就是在結構體名字後面加上(),此時,任何屬性都被初始化爲默認值。
struct Person { var name = "norman" var age = 18 var gentle = "man" func singASong() { print("《海闊天空》") }}
let person1 = Person()print("我叫\(person1.name),我今年\(person1.age)歲,性別\(person1.gentle)")//打印結果:我叫norman,我今年18歲,性別man
實例化結構體的方式二:
全部的結構體都會有一個自動生成的成員構造函數來實例化結構體,可使用它來初始化全部的成員屬性。
struct Person { var name = "norman" var age = 18 var gentle = "man" func singASong() { print("《海闊天空》") }}
let person2 = Person(name: "Lavie", age: 20, gentle: "male")print("我叫\(person2.name),我今年\(person2.age)歲,性別\(person2.gentle)")//打印結果:我叫Lavie,我今年20歲,性別male
訪問結構體實例的屬性和方法
咱們可使用點語法來訪問一個結構體實例的屬性和方法。以下:
struct Person { var name = "norman" var age = 18 var gentle = "man" func singASong() { print("《海闊天空》") }}
let person1 = Person()print("我叫\(person1.name),我今年\(person1.age)歲,性別\(person1.gentle)") // 我叫norman,我今年18歲,性別manperson1.singASong() // 《海闊天空》
若是點語法是在等號後面,或者沒有等號,那麼就是訪問;若是點語法在等號前面,就是賦值。以下:
struct Person { var name = "norman" var age = 18 var gentle = "man" func singASong() { print("《海闊天空》") }}
var person1 = Person()print("我叫\(person1.name)") // 我叫normanperson1.name = "lavie" // 賦值print("我叫\(person1.name)") // 我叫lavieperson1.singASong() // 《海闊天空》
結構體是值類型
值類型是一種當它被賦值給一個常量或者變量,或者被傳遞給函數時,會被拷貝的類型。
Swift中的枚舉、結構體等都是值類型,它在代碼傳遞中老是會被拷貝。
struct Person { var name = "norman"}
var person1 = Person()// 值類型拷貝var person2 = person1
//此時改變person2,並不會改變person1的值person2.name = "lavie"
print(person1.name) // normanprint(person2.name) // lavie
Swift中的字符串String、字典Dictionary、數組Array類型,是做爲結構體來實現的,這意味着,當String、Dictionary、Array類型的實例被賦值到一個新的常量或者變量,或被傳遞到一個函數中的時候,其實傳遞的是拷貝後的值。
OC中的NSString、NSArray和NSDictionary,他們是做爲類來實現的,因此NSString、NSArray和NSDictionary的實例對象老是做爲一個引用,而不是拷貝來實現賦值和傳遞。
類
Swift雖然推薦是面向協議編程,但其也是一門面向對象的語言。
面向對象的語言中很重要的兩個概念是:類和對象。對象是類的實例。
Swift中用class關鍵字來定義類。
定義語法
class 類名 { // 定義屬性和方法}
舉例:
class Person { var name = "norman" var age = 20 func play() { print("play") }}
該例中定義了一個名爲Person的類,該類有兩個屬性和一個方法。
類的實例
類的實例化與結構體的實例化同樣,最簡單的就是在名稱後面加一個小括號(),可是類默認沒有成員構造函數。
var person = Person()
訪問屬性和方法
類屬性方法的訪問和結構體的屬性方法的訪問是如出一轍的。
咱們可使用點語法來訪問一個類的實例的屬性和方法。以下:
class Person { var name = "norman" var age = 18 var gentle = "man" func singASong() { print("《海闊天空》") }}
let person1 = Person()print("我叫\(person1.name),我今年\(person1.age)歲,性別\(person1.gentle)") // 我叫norman,我今年18歲,性別manperson1.singASong() // 《海闊天空》
若是點語法是在等號後面,或者沒有等號,那麼就是訪問;若是點語法在等號前面,就是賦值。以下:
class Person { var name = "norman" var age = 18 var gentle = "man" func singASong() { print("《海闊天空》") }}
var person1 = Person()print("我叫\(person1.name)") // 我叫normanperson1.name = "lavie" // 賦值print("我叫\(person1.name)") // 我叫lavieperson1.singASong() // 《海闊天空》
類是引用類型
與值類型不一樣,引用類型被賦值到一個常量或者變量,或者被傳遞到一個函數中的時候,它是不會被拷貝的,而是使用的同一個對某實例的引用。
class Person { var name = "norman"}
var person1 = Person()// 引用類型var person2 = person1
//此時改變person2,會影響person1的值,由於它倆引用的是同一個對象person2.name = "lavie"
print(person1.name) // lavieprint(person2.name) // lavie
特徵運算符
因爲類是引用類型,可能有不少常量或者變量都是引用到了同一個類的實例。有時候須要找出兩個常量或者變量是否引用自同一個實例,Swift中提供了兩個特徵運算符來檢查兩個常量或者變量是否引用自相同的實例。
=== 引用自類的同一個實例
!== 沒有引用自類的同一個實例
class Person { var name = "norman"}
var person1 = Person()var person2 = person1var person3 = Person()
// 特徵運算符print(person1 === person2) // trueprint(person2 === person3) // false
繼承
一個類是能夠從另一個類那繼承方法、屬性和其餘的特性的。
當一個類從另一個類那裏繼承的時候,繼承的類就是子類,被繼承的類就是父類。
繼承的目的是爲了代碼複用。
//父類class Person { var name = "norman" func eat() { print("eat") }}
//子類class Child : Person { var school = "杭州市第一小學"}
//子類class Adult : Person { var company = "杭州魔筷"}
var person = Person()var child = Child()var adult = Adult()
//Child和Adult都繼承了其父類Person的方法person.eat()child.eat()adult.eat()
重寫(覆寫)
所謂重寫,就是子類能夠對繼承自父類的實例方法、類型方法、實例屬性、類型屬性進行覆蓋。
重寫須要在前面加上override關鍵字。
override關鍵字執行的時候,Swift編譯器會檢查重寫的類的父類(或者父類的父類)是否有與之匹配的聲明來提供重寫。
//父類class Person { var name = "norman" func eat() { print("eat") }}
//子類class Child : Person { var school = "杭州市第一小學" //重寫父類的方法 override func eat() { print("child eat") }}
//子類class Adult : Person { var company = "杭州魔筷" //重寫父類的方法 override func eat() { print("adult eat") }}
var person = Person()var child = Child()var adult = Adult()
person.eat() // eatchild.eat() // child eatadult.eat() // adult eat
若是不想父類的屬性或者方法被重寫,那麼能夠經過final關鍵字來阻止子類的重寫行爲:
//父類class Person { var name = "norman" //經過final關鍵字阻止被重寫 final func eat() { print("eat") }}
//子類class Child : Person { var school = "杭州市第一小學" //重寫父類的方法 // 此時會報錯error: instance method overrides a 'final' instance method override func eat() { print("child eat") }}
類與結構體均可以用來定義自定義的數據類型,結構體實例老是經過值來傳遞,而類實例老是經過引用來傳遞。
類的屬性介紹
在Swift的類中,屬性分爲以下三種:
存儲屬性:用於存儲類的實例的常量和變量
計算屬性:經過某種方式計算出來的屬性
類屬性:與整個類自身相關的屬性
1、存儲屬性
存儲屬性是最簡單的屬性,它做爲類實例的一部分,用於存儲常量和變量。
咱們能夠給存儲屬性提供一個默認值,也能夠在初始化方法中對其進行初始化。
class Student { var name : String? var age : Int = 19 var chineseScore : Double = 0.0 var mathScore : Double = 0.0}
//建立實例對象var student = Student()
//給存儲屬性賦值student.name = "norman"student.age = 18
student.chineseScore = 98.0student.mathScore = 96.0
本例中的name和age都是存儲屬性,用來記錄該學生的姓名和年齡。
chineseScore和mathScore也是存儲屬性,用來記錄該學生的語文分數和數學分數。
2、計算屬性
計算屬性並不存儲實際的值,而是提供一個getter和一個可選的setter來間接獲取和設置其屬性值。
計算屬性通常只提供getter方法,不提供setter方法。
若是隻提供getter方法,而不提供setter方法的話,則該計算屬性爲只讀屬性,而且能夠省略掉get{}。
class Student { //存儲屬性 var name : String? var age : Int = 19 var chineseScore : Double = 0.0 var mathScore : Double = 0.0 //計算屬性 var averageScore : Double { get { return (chineseScore + mathScore)/2 } } }
//建立實例對象var student = Student()
//給存儲屬性賦值student.name = "norman"student.age = 18
student.chineseScore = 98.0student.mathScore = 96.0
//獲取計算屬性student.averageScore // 97
本例中,averageScore是計算屬性,它的值是由chineseScore和mathScore計算得來。
須要注意的是,averageScore的定義以下:
//計算屬性 var averageScore : Double { get { return (chineseScore + mathScore)/2 } }
能夠簡化爲:
//計算屬性 var averageScore : Double { return (chineseScore + mathScore)/2 }
3、類屬性
類屬性是與類相關聯的,而不是與類的實例相關聯。
全部的類和實例都共有一份類屬性,所以在某一處修改以後,該類屬性就會被修改。
類屬性的設置和修改須要經過類來完成。
下面是類屬性的寫法:
class Student { //存儲屬性 var name : String? var age : Int = 19 var chineseScore : Double = 0.0 var mathScore : Double = 0.0 //計算屬性 var averageScore : Double { return (chineseScore + mathScore)/2 } //類屬性 static var courseCount : Int = 3}
//建立實例對象var student = Student()
//給存儲屬性賦值student.name = "norman"student.age = 18
student.chineseScore = 98.0student.mathScore = 96.0
//獲取計算屬性student.averageScore // 97
//類屬性的設值與取值Student.courseCount = 6print(Student.courseCount) // 6
4、懶加載屬性
懶加載屬性是指第一次被調用的時候纔會計算其初始值的屬性,也就是說,懶加載的對象在第一次使用的時候纔會真正被加載到內存中。
在OC中,咱們經過gettter方法來實現懶加載。
可是在Swift中,咱們是在屬性的聲明前使用lazy關鍵字來表示該屬性是延遲加載(即懶加載)的。
class Student { //懶加載屬性 //在第一次使用到該屬性的時候,執行閉包,將閉包的返回值賦值給屬性 lazy var terchers: [String] = { () -> [String] in return ["tercher1", "tercher2", "tercher3"] }()}
//建立實例對象var student = Student()
print(student.terchers) // ["tercher1", "tercher2", "tercher3"]
協議
協議的定義
協議的定義方式與類、結構體、枚舉的定義方式很是類似:
protocol SomeProtocol { //屬性 //方法}
協議中的屬性須要遵循如下幾點:
必須設置爲變量var
不能夠有默認值
必須設置是{get}仍是{get set},{get}表示只讀,{get set}表示可讀可寫
協議中的方法須要注意如下幾點:
方法不能有方法體
方法中的參數不能有默認值
protocol SomeProtocol { //屬性 var name : String {get set} //方法 func play(company : String) mutating func eat()}
協議的遵循
遵循協議的寫法跟繼承父類的寫法實際上是同樣的:
//協議protocol SomeProtocol { //屬性 var name : String {get set} //方法 func play(company : String) mutating func eat()}
//父類class Person { var age : Int = 18}
//遵循協議,繼承父類class Student : Person, SomeProtocol { //實現協議中的屬性 var name: String = "" //實現協議中的方法 func play(company: String) { print("play with \(company)") } func eat() { print("to dine") }}
協議的繼承
//父協議protocol ParentProtocol { //屬性 var name : String {get set} //方法 func play(company : String) mutating func eat()}
//子協議protocol SonProtocol : ParentProtocol { func study()}
//遵循協議class Student : SonProtocol { //實現父協議中的內容 var name: String = "" func play(company: String) { print("play with \(company)") } func eat() { print("to dine") } //實現子協議中的內容 func study() { print("study") }}
協議中方法的可選
1,optional關鍵字
protocol ParentProtocol { func play(company : String) //該方法可選 optional func eat() }
//遵循協議class Student : ParentProtocol { //實現協議中的內容 //此時能夠不實現協議中的可選方法,固然也能夠實現 func play(company: String) { print("play with \(company)") }}
2,擴展協議
protocol ParentProtocol { func play(company : String) func eat()}
extension ParentProtocol { //能夠在協議的拓展中對協議中的方法進行默認的實現 func eat() { print("eat") }}
//遵循協議class Student : ParentProtocol { //實現協議中的內容 //若是協議中的方法已經在拓展中默認實現了,這裏能夠實現也能夠不實現 func play(company: String) { print("play with \(company)") }}
咱們能夠利用協議的擴展,對協議中的一些方法進行默認實現。若是在協議的擴展中對某些方法進行了實現,那麼在遵循協議的類裏面,能夠不實現已經有了默認實現的方法。
協議的運用——代理模式
//第1步,定義一個協議,規定須要完成的任務protocol BuyTicketProtocol { func buyTicket()}
//第2步,讓具體的類或者結構體來實現協議,將任務具體化class Assistant : BuyTicketProtocol { func buyTicket() { print("祕書去買票") }}
class Scalpers : BuyTicketProtocol { func buyTicket() { print("黃牛去買票") }}
//第3步,委託方的一個配置class Person { //3.1,首先設置代理屬性 var delegate : BuyTicketProtocol? func goToShanghai() { print("準備去上海,找我的去買票") //3.2,在須要完成任務的時候經過代理來進行操做 delegate?.buyTicket() print("買到票了,準備出發") }}
//第4步,設置委託方的代理var person = Person()person.delegate = Scalpers() // 設置委託方的代理person.goToShanghai()
打印結果爲:
準備去上海,找我的去買票
黃牛去買票
買到票了,準備出發
擴展
擴展能夠爲類、結構體、枚舉、協議添加新的功能。Swift中的擴展相似於OC中的分類。
擴展能夠作的事情:
添加計算屬性
定義方法
使現有類型遵循某種協議
在Swift中,使用extension關鍵字來實現擴展。
其語法以下:
extension SomeType { // 這裏的SomeType能夠是類、枚舉、結構體,也能夠是協議 // 在這裏面去添加一些新的內容}
擴展計算屬性
擴展能夠在不動原有類型的狀況下,向已有的類型添加計算實例屬性和計算類型屬性。
extension Int { //給Int類型增長一個平方屬性 var square: Int { return self * self }}
var a = 2print(a.square) // 4
Int是結構體,上例演示了經過擴展給一個結構體增長計算實例屬性。
擴展方法
擴展一個普通方法
extension Int { func square() -> Int { return self * self }}
var a = 8print(a.square()) // 64
使現有類型遵循某協議
擴展可使既有類型遵循一個或者多個協議,協議的遵循書寫方式與原類中徹底一致。語法以下:
extension SomeClass : SomeProtocol, AnotherProtocol { //能夠用於分離原類中的代碼}
這個寫法在開發中是很是有用的,好比能夠將tableView、collectionView的代理從原控制器中給抽離出來,避免臃腫。
泛型
所謂泛型,顧名思義,就是普遍類型。也就是說,一開始不肯定是什麼類型,等到真正使用的時候,根據賦值的數據類型來肯定類型。
先來看個案例,好比如今咱們須要交換兩個Int類型的變量的值,實現以下:
//交換傳入的兩個數的值func SwapTwoInts(a : inout Int, b : inout Int) { let temp = a a = b b = temp}
var lilyAge = 20var normanAge = 26SwapTwoInts(a: &lilyAge, b: &normanAge)print(lilyAge) // 26print(normanAge) // 20
我如今又增長了一個需求,就是既須要轉換Int類型的兩個數值,也須要轉換Double類型的兩個數值,或者是轉換其餘類型的兩個數值,那怎麼辦呢?,這些方法僅僅是參數的類型不一樣,是否是針對每個類型都須要寫一個轉換方法呢?
此時就須要用到泛型了。
//泛型函數func SwapTwoValues<T>(a : inout T, b : inout T) { let temp = a a = b b = temp}
var lilyAge = 20var normanAge = 26SwapTwoValues(a: &lilyAge, b: &normanAge)print(lilyAge) // 26print(normanAge) // 20
var lilyName = "lily"var normanName = "norman"SwapTwoValues(a: &lilyName, b: &normanName)print(lilyName) // normanprint(normanName) // lily
該例中的 T 是一個類型參數(它能夠是任意名稱,咱們通常使用 T 來表示),類型參數用於指定並命名一個佔位符類型,並使用<>包裹,放在函數名後邊,好比該例中的<T>。可使用它來指定參數類型或者返回值的類型。在真正調用的時候會被實際的類型替代,如傳遞的是Int,就替換爲Int;若是傳遞的是Double,就替換爲Double等等。
泛型的類型約束
有時候咱們須要給泛型作一些約束,好比必須繼承自某個父類,或者必須遵循某些協議等,這也是能夠作到的。語法以下:
func someFunction<T : SomeClass, U : SomeProtocol>(someT : T, someU : U) {}
協議裏面的泛型——關聯類型
上面所說的是在類或者結構體、枚舉中使用泛型,在協議中是不能夠這樣使用的。協議中使用泛型,是經過 associatedtype 關鍵字。
protocol SomeProtocol { associatedtype Element func play(parameter1 : Element, parameter2 : Element)}
struct SomeStruct : SomeProtocol { func play(parameter1: String, parameter2: String) { print("play, \(parameter1), \(parameter2)") }}
var s = SomeStruct()s.play(parameter1: "666", parameter2: "norman")
說明以下:
協議中的泛型,是經過關鍵字 associatedtype 來實現的
與類、結構體或者枚舉中的泛型同樣,協議中的泛型也能夠進行類型約束(經過繼承或者遵循協議的方式)
面向協議編程
衆所周知,Swift是一門面向協議編程的語言。我所理解的面向協議編程是這樣的:針對某個須要實現的功能,可使用協議定義出接口,而後利用協議的拓展爲其提供默認的實現。若是在某地方須要這個功能,則只須要聲明遵循該協議便可。遵照某個協議的對象調用協議中聲明的方法時,若是遵循者本省沒有提供方法的實現,那麼協議擴展提供的默認實現將會被調用。
//定義一個協議protocol WatchMovieProtocol { func watchAMovie(name : String)}
//遵循協議並實現協議中的方法class Student : WatchMovieProtocol { func watchAMovie(name: String) { print("去電影院看《\(name)》") }}
上例中是一個遵循者遵循該協議,若是此時有100個遵循者都須要遵循該協議,而且該協議方法的實現都是同樣的,那麼是否須要在每個遵循者裏面都實現一下協議方法呢?
固然不須要,咱們可使用協議的拓展爲協議中的方法提供一個默認實現:
//定義一個協議protocol WatchMovieProtocol { func watchAMovie(name : String)}
//利用協議的拓展,給協議中的方法提供默認實現extension WatchMovieProtocol { func watchAMovie(name : String) { print("去電影院看《\(name)》") }}
//遵循協議class Student : WatchMovieProtocol {}
var studet = Student()studet.watchAMovie(name: "燃情歲月")
打印以下:
去電影院看《燃情歲月》
若是某一個遵循者須要獨特的實現,那麼咱們本身再實現一個協議便可:
//定義一個協議protocol WatchMovieProtocol { func watchAMovie(name : String)}
//利用協議的拓展,給協議中的方法提供默認實現extension WatchMovieProtocol { func watchAMovie(name : String) { print("去電影院看《\(name)》") }}
//遵循協議,而且自定義協議方法的實現class Student : WatchMovieProtocol { func watchAMovie(name : String) { print("學生去電影院看《\(name)》") }}
var studet = Student()studet.watchAMovie(name: "燃情歲月")
打印以下:
學生去電影院看《燃情歲月》
本文分享自微信公衆號 - iOS小生活(iOSHappyLife)。
若有侵權,請聯繫 support@oschina.cn 刪除。
本文參與「OSC源創計劃」,歡迎正在閱讀的你也加入,一塊兒分享。