在Swift 2發(fā)布時(shí),蘋(píng)果將Swift定義為一門(mén)面向協(xié)議編程的語(yǔ)言,協(xié)議在Swift中被賦予了更加強(qiáng)大、靈活的功能。相比于Objective-C的協(xié)議,Swift的協(xié)議不僅可以被用做代理,也可以用作對(duì)接口的抽象,代碼的復(fù)用。
1、面向協(xié)議編程
---依賴倒置原則:告訴我們要面向接口編程
定義:高層模塊不應(yīng)該依賴低層模塊,二者都應(yīng)該依賴其抽象;抽象不應(yīng)該依賴細(xì)節(jié);細(xì)節(jié)應(yīng)該依賴抽象。
問(wèn)題由來(lái):類A直接依賴類B,假如要將類A改為依賴類C,則必須通過(guò)修改類A的代碼來(lái)達(dá)成。這種場(chǎng)景下,類A一般是高層模塊,負(fù)責(zé)復(fù)雜的業(yè)務(wù)邏輯;類B和類C是低層模塊,負(fù)責(zé)基本的原子操作;假如修改類A,會(huì)給程序帶來(lái)不必要的風(fēng)險(xiǎn)。
解決方案:將類A修改為依賴接口I,類B和類C各自實(shí)現(xiàn)接口I,類A通過(guò)接口I間接與類B或者類C發(fā)生聯(lián)系,則會(huì)大大降低修改類A的幾率。
2、可選接口
Swift 中的protocol 所有方法都必須被實(shí)現(xiàn),不存在@optional 這樣的概念。為了實(shí)現(xiàn)可選接口有兩個(gè)辦法:(一)@objc 、(二)協(xié)議擴(kuò)展
// 只能被Class實(shí)現(xiàn),struct和enum不可以
@objc protocol StreetSnapTableViewCellDelegate : NSObjectProtocol{
// 可選
@objc optional func deleteSeeFewerPhoto(cell : DJStreetSnapTableViewCell, indexPath: IndexPath?)
func updateCellSubLikeInfoView(cell : DJStreetSnapTableViewCell, indexPath: IndexPath?, likeCount :Int)
func updateCellSubSimilarsView(cell:UITableViewCell ,indexPath: IndexPath?, selectedIndex : Int)
}
3、協(xié)議擴(kuò)展 protocol extension
// 在Swift2以后,我們可以對(duì)一個(gè)已有的protocol進(jìn)行擴(kuò)展。而擴(kuò)展中實(shí)現(xiàn)的方法作為“實(shí)現(xiàn)擴(kuò)展的類型”的“默認(rèn)實(shí)現(xiàn)”
// 通過(guò)提供protocol的extension,我們?yōu)閜rotocol提供了默認(rèn)實(shí)現(xiàn),這相當(dāng)于“變相”將protocol中的方法設(shè)定為了optional
protocol MyProtocol {
func method()
}
// 默認(rèn)實(shí)現(xiàn) ,代替optional
extension MyProtocol {
func method() {
print("Called")
}
}
struct MyStruct:MyProtocol {
}
MyStruct.method() //輸出: Called
struct MyStruct:MyProtocol {
func method() {
print("Called in struct")
}
}
MyStruct.method() //輸出: Called in struct
4、mutating 修飾方法
“Structures and enumerations are value types. By default, the properties of a value type cannot be modified from within its instance methods.”
譯:雖然結(jié)構(gòu)體和枚舉可以定義自己的方法,但是默認(rèn)情況下,實(shí)例方法中是不可以修改值類型的屬性。
protocol Vehicle {
var wheel: Int {get set}
// protocol的方法被mutating修飾,才能保證struct和enum實(shí)現(xiàn)時(shí)可以改變屬性的值
mutating func changeWheel()
}
struct Bike: Vehicle {
var wheel: Int
mutating func changeWheel() {
wheel = 4
}
}
class Car: Vehicle {
var wheel: Int = 0
func changeWheel() {
wheel = 4
}
}
var bike = Bike(wheel: 2)
bike.changeWheel()
print(bike.wheel)
let car = Car()
car.changeWheel()
print(car.wheel)
5、static 修飾靜態(tài)方法
protocol Vehicle {
static func wheel() -> Int
}
struct Bike: Vehicle {
static func wheel() -> Int {
return 2
}
}
// static: protocol、enum、struct 。class:class
class Car: Vehicle {
class func wheel() -> Int {
return 4
}
}
6、protocol 組合
1、接口隔離原則:利用 Protocol Composition 可以把協(xié)議分得非常細(xì),通過(guò)靈活的組合來(lái)滿足特定要求。
2、「&」這個(gè)操作符可不僅僅能組合協(xié)議而已,也能組合「Type + Protocol」(類型+協(xié)議)。
3、匿名使用:func checkSounds(animal: KittenLike & DogLike)
4、別名:typealias CuteLike = KittenLike & TigerLike & DogLike
// 分工詳細(xì):**接口隔離原則**告訴我們?cè)谠O(shè)計(jì)接口的時(shí)候要精簡(jiǎn)單一
protocol KittenLike {
func meow() -> String
}
protocol DogLike {
func bark() -> String
}
protocol TigerLike {
func aou() -> String
}
// 不推薦
class MysteryAnimal: KittenLike, DogLike, TigerLike {
func meow() -> String {
return "meow"
}
func bark() -> String {
return "bark"
}
func aou() -> String {
return "aou"
}
}
// 推薦
typealias CuteLike = KittenLike & TigerLike & DogLike
class CuteAnimal: CuteLike {
func meow() -> String {
return "meow"
}
func bark() -> String {
return "bark"
}
func aou() -> String {
return "aou"
}
}
struct CheckAnimal {
//
static func checkSounds(animal: KittenLike & DogLike) -> Bool {
return true
}
}
7、PATs, Protocols with Associated Type
參考:
在協(xié)議中使用范型:
// Protocols with Associated Types 舉例
struct Model {
let age: Int
}
//協(xié)議,使用關(guān)聯(lián)類型
protocol TableViewCell {
associatedtype T
func updateCell(_ data: T)
}
//遵守TableViewCell
class MyTableViewCell: UITableViewCell, TableViewCell {
typealias T = Model
func updateCell(_ data: Model) {
// do something ...
}
}