协议

247 阅读7分钟
  1. 协议语法
protocol protocol1 {
    
}

protocol protocol2 {
    
}

class Test {
    
}

class Test1: Test, protocol1, protocol2 {
    
}
  1. 属性要求
    1. 一定是var关键子的属性
    2. 属性的名字要一致
    3. 属性的类型要一致
    4. 如果协议是get只读属性,那么协议的实现可以是只读属性,也可以是可读写属性。
    5. 如果协议是get,set属性,那么协议的实行必须是可读写属性。
protocol FullName {
    var fullName: String {get}
}

class Person: FullName {
    var name: String
    var preName: String?
    init(name: String, preName: String? = nil) {
        self.name = name
        self.preName = preName
    }
    
    var fullName: String {
        var str = preName ?? ""
        if str.isEmpty {
            str = name
        }else{
            str = str + " " + name
        }
        return str
    }
}

let a = Person(name: "小明", preName: "王")
print(a.fullName)
  1. 方法要求
    1. 协议可以定义实例方法或者类型方法,类型方法必须用static关键字。
    2. 协议的遵循者要实现相应的实例方法或者类型方法,类型方法可以用static,class关键字
    3. 有参数就在协议里写上参数,有返回值就写上返回值,没有就不写。
protocol Funcation {
    func sum(one: Double, two: Double) -> Double
    static func addOne(num: Int) -> Int
}

class Test: Funcation {
    func sum(one: Double, two: Double) -> Double {
        return one + two
    }
    
    static func addOne(num: Int) -> Int {
        return num + 1
    }
}
  1. 异变方法要求
    1. 协议要在func前用mutating关键字修饰。
    2. 协议实现如果是值类型(枚举类型,结构体)也要用mutating修饰。如果是类就不需要这个关键字了。
protocol ChangeProtocol {
    mutating func change()
}

enum Switch: String, ChangeProtocol {
    case on, off
    mutating func change() {
        switch self {
        case .on:
            self = .off
        case .off:
            self = .on
        }
    }
}

class Test: ChangeProtocol {
    func change() {
        
    }
}

var a = Switch.on
a.change()
print(a)
  1. 构造器要求
protocol SomeProtocol {
    init()
}

class SomeClass {
    init() {
        
    }
}

class SubSomeClass: SomeClass, SomeProtocol {
   required override init(){
        
    }
}

class SubSomeClass1: SomeProtocol {
    required init(){
        
    }
}

class SubSomeClass2: SubSomeClass1 {
    required init(){
        
    }
}
  1. 可失败构造器要求
    1. 协议中定义了可失败构造器,那么协议的遵守者可以实现非可失败构造器,也可以实现可失败构造器。
    2. 协议中定义了不可失败构造器,那么协议的遵守者要用非可失败构造器去实现。
protocol SomeProtocol {
    init?()
}

class SomeClass: SomeProtocol {
   required init() {
        
    }
    
//    required init()? {
//
//    }
}
  1. 协议作为类型
import UIKit

protocol RandomNum {
    func random() -> Double
}

struct Dice {
    var sides: Int
    var random: RandomNum
    init(sides: Int, random: RandomNum) {
        self.sides = sides
        self.random = random
    }
    
    func roll() ->  Int{
        return Int(self.random.random() * Double(self.sides)) + 1
    }
}

struct RandomStruct: RandomNum {
    func random() -> Double {
        let Y = arc4random_uniform(100 - 0) + 0
        return Double(Y % 10) * 0.1
    }
}

let dice = Dice(sides: 6, random: RandomStruct())
print(dice.roll())
  1. 委托
//1. 委托
protocol RandomDevice {
    func roll() -> Double
}

class Dice {
    var sides: Int
    var randomDevice: RandomDevice
    init(sides: Int, randomDevice: RandomDevice) {
        self.sides = sides
        self.randomDevice = randomDevice
    }
    
    func playDiceOnce() -> Int {
        return Int(randomDevice.roll() * Double(sides)) + 1
    }
}

class LineRandomDevice: RandomDevice {
    func roll() -> Double {
        return Double((arc4random_uniform(100 - 0) + 0) % 10) * 0.1
    }
}


protocol DiceGame {
    var dice: Dice {get}
    func play()
}

protocol DiceGameTrack {
    func diceGameDidStart(diceGame: DiceGame)
    func diceGamePlay(diceGame: DiceGame, number: Int)
    func diceGameDidEnd(diceGame: DiceGame)
}

class SnakesAndLaddersGame: DiceGame {
    var finalStep = 25
    var board: [Int]
    var delegate: DiceGameTrack?
    var squire = 0
    
    init() {
        board = Array(repeating: 0, count: finalStep + 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
    }
    
    var dice: Dice = Dice(sides: 6, randomDevice: LineRandomDevice())
    func play() {
        self.delegate?.diceGameDidStart(diceGame: self)
        loop: while squire != finalStep {
            let number = dice.playDiceOnce()
            self.delegate?.diceGamePlay(diceGame: self, number: number)
            switch number + squire{
            case finalStep:
                break loop
            case let newValue where newValue > finalStep:
                continue loop
            default:
                squire += number
                squire += board[squire]
            }
        }
        self.delegate?.diceGameDidEnd(diceGame: self)
    }
}

class SnakesAndLaddersDiceGameTrack: DiceGameTrack {
    var turns = 0
    func diceGameDidStart(diceGame: DiceGame) {
        print("\(diceGame) is starting")
    }
    
    func diceGamePlay(diceGame: DiceGame, number: Int) {
        turns += 1
        print("\(diceGame) roll is \(number) playing...")
    }
    
    func diceGameDidEnd(diceGame: DiceGame) {
        print("\(diceGame) is end  \(turns)turns")
    }
}

var a = SnakesAndLaddersGame()
var b = SnakesAndLaddersDiceGameTrack()
a.delegate = b
a.play()
  1. 通过扩展来遵守协议
//2. 通过扩展遵守协议
protocol Despration {
    func despration()
}

extension SnakesAndLaddersGame: Despration {
    func despration() {
        print("fineSquire is \(self.finalStep)")
    }
}
a.despration()
  1. 有条件的遵守协议
    1. 数组中map方法 $0代表每个元素。最后map方法返回一个元素自定义的数组。
    2. 数组中的joined方法,只有当数组中的每个元素都是String类型才可以使用。
//3. 有条件的遵循协议
extension Dice: Despration {
    func despration() -> String{
        return "A \(sides)-sided dice"
    }
}
extension Array: Despration where Element: Despration {
    func despration() -> String{
        let itemsAsText = self.map { $0.despration() }
        return ("[" + itemsAsText.joined(separator: ", ") + "]")
    }
}

var d6 = Dice(sides: 6, randomDevice: LineRandomDevice())
var d12 = Dice(sides: 12, randomDevice: LineRandomDevice())
let myDice = [d6, d12]
print(myDice.despration())
  1. 空遵守
    1. 当一个类型写了所有协议的实现,满足了这个协议的所有要求,但是没有显式的遵守,这时候是不遵守的。
    2. 这个时候我们可以通过扩展将这个类型遵守这个协议并且大括号里不写内容。
protocol Description {
    var description:String{get}
    func test() -> String
}

struct Test{
    var name: String
    var description: String{
        return "name is \(name)"
    }
    
    func test() -> String {
        return "test"
    }
}

extension Test:Description{}

var a = Test(name: "小明")
print(a.description)

var b: Description = a
print(b.test())
  1. 协议类型集合
protocol Description {
    var description: String{get}
}

class Animal: Description {
    var description: String{
        return "Animal type"
    }
}

class Dog: Description {
    var description: String{
        return "Dog type"
    }
}

var a: [Description] = [Animal(), Dog()]
for item in a {
    print(item.description)
}
  1. 协议的继承
protocol Description {
    var description: String{get}
}

protocol Test: Description {
    var test: String{get}
}

class Animal: Test {
    var description: String{
        return "Animal type"
    }
    var test: String{
        return "test"
    }
}

var aAnimal = Animal()
print(aAnimal.test)
print(aAnimal.description)
  1. 类专属协议
protocol Description {
    var description: String{get}
}

protocol Test: AnyObject, Description {
    var test: String{get}
}

//下边结构体将会报错
struct Dog: Test {
    var description: String{
        return "Dog type"
    }
    var test: String{
        return "test"
    }
}

class Animal: Test {
    var description: String{
        return "Animal type"
    }
    var test: String{
        return "test"
    }
}

var aAnimal = Animal()
print(aAnimal.test)
print(aAnimal.description)
  1. 协议合成
protocol Name {
    var name: String{get}
}

protocol Age {
    var age: Int{get}
}

struct Person: Name, Age {
    var name: String
    var age: Int
}

func description(person: Name & Age){
    print("name is \(person.name)   age is \(person.age)")
}

description(person: Person(name: "小明", age: 23))
  1. 判断是遵守了哪种协议
    1. as? : 用来判断是否遵守了某个协议,如果没遵守就返回nil,如果遵守了,就返回这个协议。
    2. as!和 as?一样但是有可能触发运行时错误。
protocol AreaProtocol {
    var area: Double {get}
}

class Circle: AreaProtocol {
    let pi = 3.1415926
    var ridus: Double
    var area: Double {
        return pi * ridus * ridus
    }
    
    init(ridus: Double) {
        self.ridus = ridus
    }
}

class Country: AreaProtocol {
    var area: Double
    init(area: Double) {
        self.area = area
    }
}

class Animal {
    var legs: Int
    init(legs: Int) {
        self.legs = legs
    }
}


var objs: [AnyObject] = [
    Circle(ridus: 5.0),
    Country(area: 1300),
    Animal(legs: 4)
]

for item in objs {
    if let areaPro = item as? AreaProtocol {
        print("area = \(areaPro.area)")
    }else{
        print("no area")
    }
}
  1. 可选协议要求
    1. @objc用在协议前面
    2. @objc optional用在属性和方法前面
    3. 这种表明只有oc的类才可以遵守该协议。
import UIKit

@objc protocol CountDataSource {
    @objc optional func incerment(count: Int) -> Int
    @objc optional var countIncerment: Int{get}
}

class Count {
    var total = 0
    var dataSource: CountDataSource?
    func increment(){
        if let amount = dataSource?.incerment?(count: total){
            total += amount
        }else if let amount = dataSource?.countIncerment{
            total += amount
        }
    }
}

class CountObj: NSObject, CountDataSource{
    var countIncerment: Int{
        return 3
    }
}

//var a = Count()
//a.dataSource = CountObj()
//for _ in 1...4 {
//    a.increment()
//    print(a.total)
//}


class  ZeroSource: NSObject, CountDataSource {
    func incerment(count: Int) -> Int {
        switch count {
        case 0:
            return 0
        case let cot where cot > 0:
            return -1
        case let cot where cot < 0:
            return 1
        default:
            return 0
        }
    }
}

var b = Count()
b.dataSource = ZeroSource()
b.total = -4

for _ in 1...5{
    b.increment()
    print(b.total)
}
  1. 协议的扩展
    1. 可以给协议扩展计算属性,和方法。
    2. 被扩展的协议是可选的协议了,在类里面可以直接使用。
import UIKit
protocol TestProtocol {
    func random() -> Double
}

extension TestProtocol {
    var probability: Bool {
        return random() >= 0.5
    }
}

class TestClass: TestProtocol {
    func random() -> Double {
        let num = arc4random_uniform(100 - 0) + 0
        let count = Double(num % 10) * 0.1
        print(count)
       return count
    }
}

var a = TestClass()
print(a.probability)
  1. 为协议扩展添加约束条件
extension Collection where Element: Equatable{
    func allEqual() -> Bool {
        for item in self {
            if item != self.first {
                return false
            }
        }
        return true
    }
}

var a = [1,1,1,1,1]
var b = [1,1,1,1,1]
var c = [1,1,1,1,1,2]

print(a.allEqual())
print(b.allEqual())
print(c.allEqual())
  1. 总结
    1. 操作符
      1. as
        1. as用来向上转型,如dogObj as Animal
        2. as用来消除可选类型的警报,如dogObj as Any
      2. as?
        1. 用来向下转型,animalObj as?Dog。
        2. 用来判断是否遵守某个协议,areaObj as? AreaProtocol
      3. as!
        1. 用来向下转型,animalObj as?Dog。可能触发运行时错误
        2. 用来判断是否遵守某个协议,areaObj。可能触发运行时错误
      4. is
        1. 用来判断某个对象是否属于某个类,dogObj is Dog
      5. == 判断是否两个值相当, === 判断是否两个引用是同一个地址。
    2. 协议
      1. 当我们需要用户自定义操作时候往往用协议进行委托。如我们自己封装了一个模块,模块内部有tableView,这时候我们要用户自定义cell供我们模块内部使用,这时候我么可以用协议进行委托。我们定义一组协议,然后模块内部定义一个这种协议类型的对象,然后用这个对象的协议的方法。最后让用户去遵守这个协议,实现协议的内部方法,返回自定义的Cell。并将模块的对象进行委托即可。
      2. 作为回调。
      3. 封装一组功能,对类进行增强。如我们可以对应一组协议,然后让类去遵守这个协议,在实现协议的方法。这个过程其实是对这个类的功能增强,并且条理更清晰。