環境Xcode 11.0 beta4 swift 5.1git
示例swift
protocol SomeProtocol { // protocol definition goes here } struct SomeStructure: FirstProtocol, AnotherProtocol { // structure definition goes here } class SomeClass: SomeSuperclass, FirstProtocol, AnotherProtocol { // class definition goes here }
協議不需指定屬性是存儲或計算屬性,只需指定所需的屬性名稱和類型;協議指定了每一個屬性是可讀或可讀可寫,一般在類型後跟 {get set}
或 { get }
標識設計模式
protocol SomeProtocol { var mustBeSettable: Int { get set } var doesNotNeedToBeSettable: Int { get } }
協議中類型屬性仍然用關鍵字 static
或 class
修飾數組
protocol AnotherProtocol { static var someTypeProperty: Int { get set } }
// 只有一個屬性的協議 protocol FullyNamed { var fullName: String { get } } // 遵照協議必須要提供一個一個名爲 fullName 的可獲取實例屬性 struct Person: FullyNamed { var fullName: String } let john = Person(fullName: "John Appleseed") // john.fullName is "John Appleseed" // // 遵照 FullNamed 協議,此處用的是一個只可讀的計算屬性 class Starship: FullyNamed { var prefix: String? var name: String init(name: String, prefix: String? = nil) { self.name = name self.prefix = prefix } var fullName: String { return (prefix != nil ? prefix! + " " : "") + name } } var ncc1701 = Starship(name: "Enterprise", prefix: "USS") // ncc1701.fullName is "USS Enterprise"
協議定義中可定義實例和類型方法,與正常的方法定義相似,方法參數能夠是可變參數,但不能有方法體,且參數不能設置默認值app
protocol SomeProtocol { static func someTypeMethod() } protocol RandomNumberGenerator { func random() -> Double } // 示例以下 class LinearCongruentialGenerator: RandomNumberGenerator { var lastRandom = 42.0 let m = 139968.0 let a = 3877.0 let c = 29573.0 func random() -> Double { lastRandom = ((lastRandom * a + c) .truncatingRemainder(dividingBy:m)) return lastRandom / m } } let generator = LinearCongruentialGenerator() print("Here's a random number: \(generator.random())") // Prints "Here's a random number: 0.3746499199817101" print("And another one: \(generator.random())") // Prints "And another one: 0.729023776863283"
協議中方法可用 mutatuing
修飾,這位遵照此協議的方法能夠修改屬性值(結構體、枚舉也能夠),且可在實現方法時可省略此關鍵字dom
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 is now equal to .on
協議中可定義初始化器讓遵照的類型實現,但協議中的初始化器沒有 {}
或 函數體,實現類實現初始化器(便捷或指定初始化器)必需加 required
修飾符ide
protocol SomeProtocol { init(someParameter: Int) } class SomeClass: SomeProtocol { required init(someParameter: Int) { // initializer implementation goes here } }
若是一個子類重寫父類的指定初始化器同時遵照協議的初始化器的要求,必需同時用 required
和 override
修飾符函數
protocol SomeProtocol { init() } // class SomeSuperClass { init() { // initializer implementation goes here } } // class SomeSubClass: SomeSuperClass, SomeProtocol { // "required" from SomeProtocol conformance; "override" from SomeSuperClass required override init() { // initializer implementation goes here } }
能夠用在字典、數組、其它容器中元素的類型oop
class Dice { let sides: Int let generator: RandomNumberGenerator init(sides: Int, generator: RandomNumberGenerator) { self.sides = sides self.generator = generator } func roll() -> Int { return Int(generator.random() * Double(sides)) + 1 } } var d6 = Dice(sides: 6, generator: LinearCongruentialGenerator()) for _ in 1...5 { print("Random dice roll is \(d6.roll())") } // Random dice roll is 3 // Random dice roll is 5 // Random dice roll is 4 // Random dice roll is 5 // Random dice roll is 4
代理是一種重要的設計模式,示例代碼學習
protocol DiceGame { var dice: Dice { get } func play() } protocol DiceGameDelegate: AnyObject { func gameDidStart(_ game: DiceGame) func game(_ game: DiceGame, didStartNewTurnWithDiceRoll diceRoll: Int) func gameDidEnd(_ game: DiceGame) } class SnakesAndLadders: DiceGame { let finalSquare = 25 let dice = Dice(sides: 6, generator: LinearCongruentialGenerator()) var square = 0 var board: [Int] init() { board = Array(repeating: 0, count: finalSquare + 1) board[03] = +08; board[06] = +11; board[09] = +09; board[10] = +02 board[14] = -10; board[19] = -11; board[22] = -02; board[24] = -08 } weak var delegate: DiceGameDelegate? // 通常用 weak func play() { square = 0 delegate?.gameDidStart(self) gameLoop: while square != finalSquare { let diceRoll = dice.roll() delegate?.game(self, didStartNewTurnWithDiceRoll: diceRoll) switch square + diceRoll { case finalSquare: break gameLoop case let newSquare where newSquare > finalSquare: continue gameLoop default: square += diceRoll square += board[square] } } delegate?.gameDidEnd(self) } } class DiceGameTracker: DiceGameDelegate { var numberOfTurns = 0 func gameDidStart(_ game: DiceGame) { numberOfTurns = 0 if game is SnakesAndLadders { print("Started a new game of Snakes and Ladders") } print("The game is using a \(game.dice.sides)-sided dice") } func game(_ game: DiceGame, didStartNewTurnWithDiceRoll diceRoll: Int) { numberOfTurns += 1 print("Rolled a \(diceRoll)") } func gameDidEnd(_ game: DiceGame) { print("The game lasted for \(numberOfTurns) turns") } } let tracker = DiceGameTracker() let game = SnakesAndLadders() game.delegate = tracker game.play() // Started a new game of Snakes and Ladders // The game is using a 6-sided dice // Rolled a 3 // Rolled a 5 // Rolled a 4 // Rolled a 5 // The game lasted for 4 turns
擴展能夠爲現有的類添加屬性、方法、下標,所以能夠添加協議可能須要的任何要求
protocol TextRepresentable { var textualDescription: String { get } } extension Dice: TextRepresentable { var textualDescription: String { return "A \(sides)-sided dice" } } let d12 = Dice(sides: 12, generator: LinearCongruentialGenerator()) print(d12.textualDescription) // Prints "A 12-sided dice" extension SnakesAndLadders: TextRepresentable { var textualDescription: String { return "A game of Snakes and Ladders with \(finalSquare) squares" } } print(game.textualDescription) // Prints "A game of Snakes and Ladders with 25 squares"
有條件的遵照協議
// Array 中的元素要遵照 TextRepresentable 協議 extension Array: TextRepresentable where Element: TextRepresentable { var textualDescription: String { let itemsAsText = self.map { $0.textualDescription } return "[" + itemsAsText.joined(separator: ", ") + "]" } } let myDice = [d6, d12] print(myDice.textualDescription) // Prints "[A 6-sided dice, A 12-sided dice]"
採用擴展申明協議
struct Hamster { var name: String var textualDescription: String { return "A hamster named \(name)" } } extension Hamster: TextRepresentable {} let simonTheHamster = Hamster(name: "Simon") // 這裏要顯示申明類型 let somethingTextRepresentable: TextRepresentable = simonTheHamster print(somethingTextRepresentable.textualDescription) // Prints "A hamster named Simon"
示例
let things: [TextRepresentable] = [game, d12, simonTheHamster] for thing in things { print(thing.textualDescription) } // A game of Snakes and Ladders with 25 squares // A 12-sided dice // A hamster named Simon
示例
protocol InheritingProtocol: SomeProtocol, AnotherProtocol { // protocol definition goes here } protocol PrettyTextRepresentable: TextRepresentable { var prettyTextualDescription: String { get } } extension SnakesAndLadders: PrettyTextRepresentable { var prettyTextualDescription: String { var output = textualDescription + ":\n" for index in 1...finalSquare { switch board[index] { case let ladder where ladder > 0: output += "▲ " case let snake where snake < 0: output += "▼ " default: output += "○ " } } return output } } print(game.prettyTextualDescription) // A game of Snakes and Ladders with 25 squares: // ○ ○ ▲ ○ ○ ▲ ○ ○ ▲ ▲ ○ ○ ○ ▼ ○ ○ ○ ○ ▼ ○ ○ ▼ ○ ▼ ○
能夠限制協議只能類來遵照,經過添加 AnyObject
協議在繼承列表中,若是結構體或枚舉遵照會報運行時錯誤
protocol SomeClassOnlyProtocol: AnyObject, SomeInheritedProtocol { // class-only protocol definition goes here }
用 &
符號將多個協議鏈接起來
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!" // // 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) // Prints "Hello, Seattle!"
is
實例遵照協議返回 true, 不然 falseas?
返回一個協議類型的可選值,若是不遵照協議則是 nilas!
強制解包,若是失敗觸發運行時錯誤
protocol HasArea { var area: Double { get } } class Circle: HasArea { let pi = 3.1415927 var radius: Double var area: Double { return pi * radius * radius } init(radius: Double) { self.radius = radius } } class Country: HasArea { var area: Double init(area: Double) { self.area = area } } class Animal { var legs: Int init(legs: Int) { self.legs = legs } } let objects: [AnyObject] = [ Circle(radius: 2.0), Country(area: 243_610), Animal(legs: 4) ] for object in objects { if let objectWithArea = object as? HasArea { print("Area is \(objectWithArea.area)") } else { print("Something that doesn't have an area") } } // Area is 12.5663708 // Area is 243610.0 // Something that doesn't have an area
用 optional
修飾,協議和可選需求都必需用 @objc
標記,被標記的協議只能是OC類或其它 @objc
類可用,枚舉結構體不可用
@objc protocol CounterDataSource { @objc optional func increment(forCount count: Int) -> Int @objc optional var fixedIncrement: Int { get } } class Counter { var count = 0 var dataSource: CounterDataSource? func increment() { if let amount = dataSource?.increment?(forCount: count) { count += amount } else if let amount = dataSource?.fixedIncrement { count += amount } } } class ThreeSource: NSObject, CounterDataSource { let fixedIncrement = 3 } var counter = Counter() counter.dataSource = ThreeSource() for _ in 1...4 { counter.increment() print(counter.count) } // 3 // 6 // 9 // 12 class TowardsZeroSource: NSObject, CounterDataSource { func increment(forCount count: Int) -> Int { if count == 0 { return 0 } else if count < 0 { return 1 } else { return -1 } } } counter.count = -4 counter.dataSource = TowardsZeroSource() for _ in 1...5 { counter.increment() print(counter.count) } // -3 // -2 // -1 // 0 // 0
能夠爲協議添加擴展,擴展裏能夠添加方法、計算屬性、下標、初始化器等,這樣類型的一致性或全局函數的行爲可在此實現
extension RandomNumberGenerator { func randomBool() -> Bool { return random() > 0.5 } } let generator = LinearCongruentialGenerator() print("Here's a random number: \(generator.random())") // Prints "Here's a random number: 0.3746499199817101" print("And here's a random Boolean: \(generator.randomBool())") // Prints "And here's a random Boolean: true"
提供默認的實現
extension PrettyTextRepresentable { var prettyTextualDescription: String { return textualDescription } }
協議擴展添加約束
extension Collection where Element: Equatable { func allEqual() -> Bool { for element in self { if element != self.first { return false } } return true } } let equalNumbers = [100, 100, 100, 100, 100] let differentNumbers = [100, 100, 200, 100, 200] print(equalNumbers.allEqual()) // Prints "true" print(differentNumbers.allEqual()) // Prints "false"