swift 协议_swift协议 - CSDN
  • 主要介绍了深入解析Swift语言中的协议,是Swift入门学习中的基础知识,需要的朋友可以参考下
  • Swift 常见协议

    2020-01-17 14:50:17
    1 Hashable 协议 class m1:Hashable{ var name:String = "" var age:Int? // swift 4.1 版本被废弃了 var hashValue:Int{ get{ // 按照自己的规则生成 return name.hashValue * age.ha...

    1 Hashable 协议

    class m1:Hashable{
        var name:String = ""
        var age:Int?
    //    swift 4.1 版本被废弃了
        var hashValue:Int{
            get{
    //            按照自己的规则生成
                return name.hashValue * age.hashValue
            }
        }
    //    swift 4.2
        func hash(into hasher: inout Hasher) {
            hasher.combine(name)
            hasher.combine(age)
        }
        
        static func == (lhs: m1, rhs: m1) -> Bool {
            return lhs.name == rhs.name
        }
        
        
    }
    

    Hashable协议

    展开全文
  • Swift协议专题

    2019-01-18 16:23:34
    1. 协议初体验 强调的几点: (1)协议里只能用var并且一定要注明是只读还是可读可写 (2)协议可以规定只被类继承,不能规定只被结构体继承 (3)即使协议中是只读的,但是我继承的类或者结构体仍然可以用var来...

    1. 协议初体验

    强调的几点:

    (1)协议里只能用var并且一定要注明是只读还是可读可写

    (2)协议可以规定只被类继承,不能规定只被结构体继承

    (3)即使协议中是只读的,但是我继承的类或者结构体仍然可以用var来实现,相当于在只读的基础上,多加了一个可写功能,但是并不破坏原有可读的属性,所以是允许的。反之不行,如果原来在协议里就是定义可读可写,则在继承的类或者结构体中不能用let去定义,只能用var

    (4)属性可以是协议类型的,并且可以将一个实现过该协议的结构体或者类类型的实例赋值给这个属性,但是这个属性仍要优先遵循协议里面的相关约束

    (5)协议也可以有构造函数,继承协议的类的构造函数一定要用required,当然特例是类前面有final

       (6) 协议的属性,继承之后必须赋初值,不管是直接赋初值也好还是以构造函数的方式也好,还是以计算型属性的方式也好。注意,如果要以计算型属性的方式来实现协议中的属性,就要看协议中是只读还是可读可写,对应设置计算型属性的getter和setter方法

    具体代码如下

    import Foundation
    
    protocol Pet {
        
        var name: String {get set} // 继承他的时候不一定非要是计算型属性
        let birthPlace: String {get} // 只读
        
        func playWith()
        func fed(food: String)
    }
    
    struct Dog: Pet {
        var name: String = "Puppy" // 这里不能写let,因为协议中规定是可读可写,你这里相当于不遵守协议了
        var birthPlace = "Wuhan" // 协议里面是let,这里是var,相当于是在可读的基础上我加了一个可写
        
        func playWith() {
            print("Happy!")
        }
        
        func fed(food: String = "bone") {
            print("I love eating \(food)!")
        }
        
        mutating func changeName(newName: String) {
            name = newName
        }
    }
    
    var myDog: Dog = Dog()
    var aPet: Pet = myDog // 这里和继承那一章很像,Pet类型的aPet可以存放其子类的对象
    
    myDog.birthPlace = "Hankou" // 不报错,因为Dog结构体中是可读可写的
    aPet.birthPlace = "Wuchang" // 报错,因为Pet协议中是只读的
    

    2. 协议和构造函数

    import Foundation
    
    protocol Pet {
        
        var name: String {get set} // 继承他的时候不一定非要是计算型属性
        var birthPlace: String {get} // 只读
        
        func playWith()
        func fed(food: String)
        
        init(name: String) // 协议也可以有构造函数
    }
    
    class Animal {
        var type: String = "mammal"
    }
    
    class Dog: Animal, Pet {
        var name: String = "Puppy" // 这里不能写let,因为协议中规定是可读可写,你这里相当于不遵守协议了
        var birthPlace = "Wuhan" // 协议里面是let,这里是var,相当于是在可读的基础上我加了一个可写
        
        required init(name: String) { // 子类也必须继承
            self.name = name
        }
        
        func playWith() {
            print("Happy!")
        }
        
        func fed(food: String = "bone") {
            print("I love eating \(food)!")
        }
        
        func changeName(newName: String) {
            name = newName
        }
    }
    
    class Bird: Animal {
        var name: String = "Little bird"
        init(name: String) {
            self.name = name
        }
    }
    
    class Parrot: Bird, Pet {
        required override init(name: String) { // 这里的required是协议必须遵守的,要加required,要加override是因为构造函数和父类一样,所以要加override关键字
            super.init(name: name + " " + name)
        }
        
        func playWith() {
            print("gugugu")
        }
        
        func fed(food: String) {
            print("Thanks~")
        }
        
        let birthPlace: String = "Wuhan" // 这里没有name,是因为虽然Pet中规定了必须要有name,但是Parrot的父类已经有name了所以不需要
    }
    

    3. 举个?

    import UIKit
    protocol Pet {
        var name: String {get set}
    }
    
    protocol Flyable {
        var flySpeed: Double {get}
        var flyHeight: Double {get}
    }
    
    class Animal {
        
    }
    
    class Dog: Animal, Pet {
        var name = "puppy"
    }
    
    class Cat: Animal, Pet {
        var name = "Kitten"
    }
    
    class Bird: Animal, Flyable {
        var flySpeed: Double
        var flyHeight: Double
        
        init(flySpeed: Double, flyHeight: Double) {
            self.flySpeed = flySpeed
            self.flyHeight = flyHeight
        }
    }
    
    class Parrot: Bird, Pet {
        var name: String
    
        init(name: String, flySpeed: Double, flyHeight: Double) {
            self.name = name + " " + name
            super.init(flySpeed: flySpeed, flyHeight: flyHeight) // 子类指定的构造函数一定要用init
        }
    }
    
    class Sparrow: Bird {
        var color = UIColor.gray
    }
    
    class Vehicle {
        
    }
    
    class Plane: Vehicle, Flyable {
        var flySpeed: Double
        var flyHeight: Double
        var model: String
        
        init(model: String, flySpeed: Double, flyHeight: Double) {
            self.model = model
            self.flySpeed = flySpeed
            self.flyHeight = flyHeight
        }
    }
    
    var dog = Dog()
    var cat = Cat()
    var parrot = Parrot(name: "shijie", flySpeed: 10, flyHeight: 100)
    
    let pets: [Pet] = [dog, cat, parrot]
    for pet in pets { // 多态性体现,这三个都是宠物,因此可以输出他们的名字
        print(pet.name)
    }
    
    var sparrow = Sparrow(flySpeed: 15, flyHeight: 200)
    var plane = Plane(model: "Boeing 747", flySpeed: 800, flyHeight: 100_000)
    
    let flyers: [Flyable] = [parrot, sparrow, plane] // 多态性的体现
    for flyer in flyers {
        print("Fly speed: ", flyer.flySpeed, "Fly height: ", flyer.flyHeight)
    }
    

    4. 关联值类型,同一种属性,可能对于不同的继承者来说需要的类型不一样,为了代码的可重用性,可以在协议里用associatedtype来表示typealias

    代码如下

    import UIKit
    
    // 对Double进行扩展,增加两个计算型属性,以Weight的kg为单位
    extension Double {
        typealias Weight = Double // 这句话的目的是为了语义清晰,表示我这里的g是代表中重量,人家看代码的时候也好看
        var g: Weight { // 计算型属性不能有等号 =,不然报错
            return self / 1000.0
        }
        var t: Weight {
            return self * 1000.0
        }
    }
    
    // 同理
    extension Int {
        typealias Weight = Int
        var g: Weight { // 计算型属性不能有等号 =,不然报错
            return self / 1000
        }
        var t: Weight {
            return self * 1000
        }
    }
    
    protocol WeightCalculable {
        associatedtype WeightType // 关联类型,这里的类型就是WeighType,对于不同的继承者来说可能需要的类型也不一样
        var weight: WeightType {get set} // 这里设置是可读可写的,如果继承的类要用计算型属性的话,就要分别设置get方法和set方法
    }
    
    class iPhone: WeightCalculable {
        typealias WeightType = Double
        var weight: WeightType { //  协议里面设置的是可读可写的,我这里又想用计算型属性,那么就只好用getter和setter方法咯
            get {
                return 114.0.g
            }
            
            set {
                print(newValue)
            }
        }
    }
    
    class Ship: WeightCalculable {
        typealias WeightType = Int
        var weight: WeightType
        init(weight: WeightType) {
            self.weight = weight
        }
    }
    
    let ship = Ship(weight: 20_000.t)
    ship.weight // 20_000_000
    
    

    5. 标准库中的常用协议Equatable、Comparable和CustomStringConvertible以及仿C风格的改写

    import Foundation
    
    struct Record {
        var wins: Int
        var losses: Int
    }
    
    extension Record: Equatable { // 对于遵循Equatable协议的结构体或者类,必须要重载 ==
        
    }
    
    //  运算符重载必须放在外面,因为协议里面是放新添的东西,而这个是重载不是新添,因此不能放在里面,而且必须紧跟扩展的协议之后
    func == (left: Record, right: Record) -> Bool {
        return left.wins == right.wins && left.losses == right.losses
    }
    
    extension Record: Comparable { // 遵循Comparable协议只用重载 < 就行了,加上 ==,系统自动加上剩下的比较运算符的重载
        
    }
    // 同理,运算符重载应该放在外面
    func < (left: Record, right: Record) -> Bool {
        if left.wins != right.wins {
            return left.wins < right.wins
        } else if left.losses != right.losses {
            return left.losses > right.losses
        } else {
            return false
        }
    }
    
    extension Record: CustomStringConvertible { // 遵循CustomStringConvertible这个协议,只用重写description这个计算型属性就行了
        // 当直接print(结构体名)的时候,可以自定义输出格式,而不是系统自带的格式
        var description: String {
            return "WINS: \(wins), LOSS: \(losses)"
        }
    }
    
    // 可以通过下面的扩展来模仿C语言中if的写法
    extension Int {
        public var boolValue: Bool {
            return self != 0
        }
    }
    
    let record1 = Record(wins: 10, losses: 5)
    let record2 = Record(wins: 8, losses: 2)
    
    record1 == record2
    record1 >= record2
    print(record1)
    
    if record1.wins.boolValue { // 仿C风格
        print("record1起码赢了一场")
    }
    

     

    6. 扩展协议和默认实现

    想强调的几点,根据个人经验总结,仅供参考,如有错误请各位大神指出,感激不尽!小弟这里也思考了很久!

    (1)扩展里面的计算型属性和函数必须要有具体实现

    (2)可以对一个协议进行扩展,这里扩展的内容我分为三种情况

        <1> 如果该协议(称作协议A)还继承了其他协议(称作协议B),我此时可以扩展这个协议B里面的的计算型属性和方法,即相当于实现了默认实现,那么一旦有结构体或者类继承了协议A,则可以不用显式地再实现一遍刚刚扩展里面实现过的计算型属性或者方法,但是也可以再实现一遍,介时会覆盖原有默认实现。因此,如果想在继承协议A的类或者结构体里面重写协议B的属性或者方法,那么干脆可以不在extension里面进行默认实现,反正就算实现到时候也会被覆盖,何必呢是吧。

        <2> 如果扩展的是协议里原有的方法或者属性,则属于多此一举,因为就算你扩展了,到时候在继承协议A的类或者结构体里面还是要在实现一遍,不然会报错,因此没有必要去扩展协议里面本来就存在的东西,切记!

        <3> 我们还可以扩展该协议A和协议B所没有的一些计算型属性和方法 ,这也是一种默认实现,这样和<1>一样,我们可以选择不再继承协议A的结构体或者方法中重写刚刚说的计算型属性或者方法,如果偏要实现一遍,那么会覆盖原有extension里面的默认实现。

    Ps:对于情况<2>,可以这么改,既然你想默认实现,那么就没有必要在原有的protocol中进行声明,直接按情况<3>来就好了,也就是说,你不应该把你想进行默认实现的函数或者计算型属性放在原有协议里,应该直接放在扩展里。

    代码如下

    import Foundation
    
    protocol Record: CustomStringConvertible {
        var wins: Int {get}
        var losses: Int {get}
        
        func winningPercent() -> Double
    }
    
    extension Record {
        
        //  情况<1>,我们也可以选择不在扩展里面进行默认实现,在继承的类或者结构体里面进行
        var description: String {
            return "WINS: \(wins), LOSSES: \(losses)"
        }
        
        // 情况<2> 多此一举,必须删掉
        func winningPerfect() -> Double {
            return Double(wins) / Double(gamePlayed)
        }
        
        // 情况<3>
        func showWins() {
            print("WE WIN \(wins) TIMES!")
        }
        
        // 情况<3>
        var gamePlayed: Int {
            return wins + losses
        }
        
        // 情况<3>
        func hhh() -> () {
            print("hhh")
        }
    }
    
    struct BaseballRecord: Record {
        
        var wins: Int
        var losses: Int
    
        func winningPercent() -> Double { // 不能删,就算extension里面实现了也不能删,删了就报错
            return Double(wins) / Double(gamePlayed)
        }
        
    //    var description: String {
    //        return "WWWWWINS: \(wins), LOSSES: \(losses)"
    //    }
        
        
    //    func hhh() -> () {
    //        print("sss")
    //    }
        
    }
    
    let base = BaseballRecord(wins: 2, losses: 1)
    print(base) // 默认实现
    base.hhh() // 默认实现
    

    当然,我们还可以对已有的系统协议进行扩展

    extension CustomStringConvertible {
        var descriptionWithDate: String {
            return Date().description + " " + description
        }
    }
    print(base.descriptionWithDate)
    

    7. 协议与where初体验

    import Foundation
    
    protocol Record: CustomStringConvertible {
        var wins: Int {get}
        var losses: Int {get}
    }
    
    extension Record {
        var description: String {
            return "WINS: \(wins), LOSSES: \(losses)"
        }
        
        func winningPerfect() -> Double {
            return Double(wins) / Double(gamePlayed)
        }
        
        var gamePlayed: Int {
            return wins + losses
        }
    
    }
    
    // 有些比赛允许平局
    protocol Tieable {
        var ties: Int {get}
    }
    
    // 如果某个类它即继承了Record,又遵循了平局的协议,则应该重写winningPerfect()和gamePlayed以覆盖原有的方法和计算型属性
    extension Record where Self: Tieable {
        func winningPerfect() -> Double {
            return Double(wins) / Double(gamePlayed)
        }
        
        var gamePlayed: Int {
            return wins + losses + ties
        }
    }
    
    class BaseballRecord: Record {
        
        var wins: Int
        var losses: Int
        
        init(wins: Int, losses: Int) {
            self.wins = wins
            self.losses = losses
        }
    }
    
    class FootballRecord: Record, Tieable {
        var wins: Int
        var losses: Int
        var ties: Int
        
        init(wins: Int, losses: Int, ties: Int) {
            self.wins = wins
            self.losses = losses
            self.ties = ties
        }
    }
    
    let baseballRecord = BaseballRecord(wins: 5, losses: 10)
    let footballRecord = FootballRecord(wins: 1, losses: 1, ties: 1)
    
    baseballRecord.winningPerfect() // 0.3333333
    footballRecord.winningPerfect() // 0.3333333
    

    8. 协议聚合(可以理解为一种约束,表示某个变量只能继承某些协议,这样才生效)

    用 & 来分隔协议

    import Foundation
    
    protocol Record: CustomStringConvertible {
        var wins: Int {get}
        var losses: Int {get}
    }
    
    extension Record {
        var description: String {
            return "WINS: \(wins), LOSSES: \(losses)"
        }
        
        func winningPerfect() -> Double {
            return Double(wins) / Double(gamePlayed)
        }
        
        var gamePlayed: Int {
            return wins + losses
        }
    
    }
    
    // 有些比赛允许平局
    protocol Tieable {
        var ties: Int {get}
    }
    
    // 如果某个类它即继承了Record,又遵循了平局的协议,则应该重写winningPerfect()和gamePlayed以覆盖原有的方法和计算型属性
    extension Record where Self: Tieable {
        func winningPerfect() -> Double {
            return Double(wins) / Double(gamePlayed)
        }
        
        var gamePlayed: Int {
            return wins + losses + ties
        }
    }
    
    protocol Prizeable {
        func isPrizeable() -> Bool
    }
    
    class BaseballRecord: Record, Prizeable {
        
        var wins: Int
        var losses: Int
        
        init(wins: Int, losses: Int) {
            self.wins = wins
            self.losses = losses
        }
        
        func isPrizeable() -> Bool {
            return winningPerfect() > 0.4
        }
        
    }
    
    class FootballRecord: Record, Tieable, Prizeable {
        var wins: Int
        var losses: Int
        var ties: Int
        
        init(wins: Int, losses: Int, ties: Int) {
            self.wins = wins
            self.losses = losses
            self.ties = ties
        }
        
        func isPrizeable() -> Bool {
            return winningPerfect() > 0.1 && wins > 2
        }
    }
    
    struct Student: Prizeable, CustomStringConvertible {
        var name: String
        var score: Int
        var description: String {
            return name
        }
        func isPrizeable() -> Bool {
            return score > 90
        }
        init(name: String, score: Int) {
            self.name = name
            self.score = score
        }
    }
    
    // 协议聚合,这里表示one必须要继承Prizeable和CustomStringConvertible两个协议才能生效
    func award(_ one: Prizeable & CustomStringConvertible) {
        if one.isPrizeable() {
            print(one.description)
            print("You are very good!")
        } else {
            print(one.description)
            print("you are so bad!")
        }
    }
    
    let baseballRecord = BaseballRecord(wins: 5, losses: 10)
    let footballRecord = FootballRecord(wins: 1, losses: 1, ties: 1)
    let student = Student(name: "shijie", score: 100)
    
    award(baseballRecord)
    award(footballRecord)
    award(student)
    

    9. 泛型约束

    小tips:虽然我们说协议可以当做是一种类型,但是也有特例,下面的协议就不能当做一种类型。

    <1> Comparable这个协议不能被当做一种类型,因为Comparable里面的左右两边是Self这种类型,而我们知道Self是一种类型,这相当于自己调用自己,Swift不允许这样。

    <2> 如果一个协议里面有关联值,即含有关键字asscoiatedtype,那么也不能当做是一种类型,因为属性的返回值类型都不确定。

    那么怎么解决呢?只能通过泛型约束来解决。

    ?如下

    import Foundation
    
    protocol Prizable {
        func isPrizable() -> Bool
    }
    
    struct Student: Prizable, CustomStringConvertible, Equatable, Comparable {
        var name: String
        var score: Int
        var description: String {
            return name
        }
        func isPrizable() -> Bool {
            return score > 90
        }
        init(name: String, score: Int) {
            self.name = name
            self.score = score
        }
    }
    
    func == (left: Student, right: Student) -> Bool {
        return left.score == right.score
    }
    
    func < (left: Student, right: Student) -> Bool {
        return left.score < right.score
    }
    
    func getTopOne<T: Comparable>(seq: [T]) -> T { // 返回值也是一个可比较的类型
        assert(!seq.isEmpty)
        return seq.reduce(seq[0]) {
            (a: T, b: T) -> T in
            return max(a, b)
        }
    }
    
    
    // 这个人不仅分数第一,还得是可以奖励的
    func getPrizableOne<T: Comparable & Prizable> (seq:[T]) -> T?{
        return seq.reduce(nil) {
            (tempTop: T?, contender: T) -> T? in // reduce可以细细品一下
            guard contender.isPrizable() else {
                return tempTop
            }
    
            guard let tempTop = tempTop else {
                return contender
            }
    
            return max(tempTop, contender)
        }
    }
    
    let student1 = Student(name: "shijie", score: 100)
    let student2 = Student(name: "Mike", score: 20)
    let student3 = Student(name: "July", score: 80)
    let student4 = Student(name: "Ann", score: 0)
    
    let studentArr = [student1, student2, student3, student4]
    
    getTopOne(seq: studentArr) // shijie
    getPrizableOne(seq: studentArr) // shijie
    

    今天学到了reduce函数式编程的一些用法,这里把reduce拿出来单独说一下

    func reduce<Result>(_ initialResult: Result, _ nextPartialResult: (Result, T) 
    throws -> Result) rethrows -> Result

    闭包里面的第一个参数和返回值得和reduce整体返回的类型一样,第二个参数可以随意,但是要是可操作的类型。

    10. 可选的协议方法

    如果协议中含有可选的协议方法,则应在协议前加上@objc,同时对应的函数前加上@objc optional

    import UIKit
    
    // 如果协议中含有可选的协议方法,则应在协议前加上@objc,同时对应的函数前加上@objc optional
    @objc protocol TurnBasedGameDelegate {
        func gameStart()
        func playerMove()
        func gameEnd()
    
        func gameOver() -> Bool
    
        @objc optional func turnStart() // 可选的方法,可以不必实现
    
        @objc optional func turnEnd() // 同上
    }
    
    protocol TurnBasedGame {
        var turn: Int {get set}
        func play()
    }
    
    class SinglePlayerTurnBasedGame: TurnBasedGame {
        var delegate: TurnBasedGameDelegate!
        var turn = 0
    
        func play() {
            delegate.gameStart()
            while !delegate.gameOver() {
                turn += 1
                delegate.turnStart?()
                print("ROUND", turn, ":")
                delegate.playerMove()
                delegate.turnEnd?()
            }
            delegate.gameEnd()
        }
    }
    
    
    class RockPaperSscissors: SinglePlayerTurnBasedGame, TurnBasedGameDelegate {
        enum Shape: Int, CustomStringConvertible {
            case Rock // 0
            case Scissors // 1
            case Paper // 2
    
            // 枚举里面也可以有函数
            func beat(shape: Shape) -> Bool { // 看自己能否打败传进来的参数
                return (self.rawValue + 1) % 3 == shape.rawValue // 这个可以体会一下
            }
    
            var description: String { // 输出该变量的时候应该是这种格式
                switch self {
                case .Paper:
                    return "Paper"
                case .Rock:
                    return "Rock"
                case .Scissors:
                    return "Scissors"
                }
            }
        }
    
        var wins = 0
        var otherWins = 0
    
        override init() {
            super.init()
            delegate = self
        }
    
        static func go() -> Shape {
            return Shape(rawValue: Int(arc4random()) % 3)!
        }
    
        func gameStart() {
            wins = 0
            otherWins = 0
            print("== Rock Paper Scissor ==")
        }
    
        func gameOver() -> Bool {
            return wins == 2 || otherWins == 2
        }
    
        func gameEnd() {
            if wins == 2 {
                print("AFTER \(turn) ROUNDS, YOU WIN!")
            } else {
                print("AFTER \(turn) ROUNDS, YOU LOSE...")
            }
        }
    
        func playerMove() {
            let yourShape = RockPaperSscissors.go()
            let otherShape = RockPaperSscissors.go()
            print("Your: \(yourShape)")
            print("Other: \(otherShape)")
    
            if yourShape.beat(shape: otherShape) {
                print("You win this round")
                wins += 1
            } else if otherShape.beat(shape: yourShape) {
                print("You lose this round")
                otherWins += 1
            } else {
                print("Tie in this round")
            }
        }
    
        func turnStart() {
            print("++++++++++++++")
        }
    
        func turnEnd() {
            print("--------------")
            print("")
        }
    }
    
    let rockPaperScissors = RockPaperSscissors()
    rockPaperScissors.play()
    

    展开全文
  • swift 协议的使用方法和场景

    千次阅读 2017-06-27 17:34:35
    协议swift一个重要的部分,类似于Java中的接口,但是还不是很一样。相比较OC,swift协议更加灵活,它可以应用在很多场景,使整个项目的框架结构更加易于延展。 一、什么场景下使用协议协议与类类似,可以被继承...

    协议是swift一个重要的部分,类似于Java中的接口,但是还不是很一样。相比较OC,swift中协议更加灵活,它可以应用在很多场景,使整个项目的框架结构更加易于延展。

    一、什么场景下使用协议

    协议与类类似,可以被继承,当继承某个协议之后就要给协议所定义的属性赋值并且实现协议中的方法。

    既然协议与类这么类似,那我们为什么不全部用类来实现,为什么还要用到协议?
    举个简单的例子,有一只猫和狗,他们都属于宠物,用类去实现就要这样操作,定义一个父类叫做宠物,里面有喂食和玩耍两个方法,猫和狗都继承与宠物这个父类。这样操作自然可以实现,但是要知道,猫和狗不都是宠物,这里把宠物定义成父类就不是很合适,这里应该把宠物定义成协议就相对合适很多啦

    二、协议的使用方法

    1、协议定义

    // 协议定义通过关键字protocol
    protocol SomeProtocol {
        // 协议定义
    }
    
    // 协议可以继承一个或者多个协议
    protocol SomeProtocol2 :SomeProtocol {
        // 协议定义
    }
    
    // 结构体实现协议
    struct SomeStructure : SomeProtocol,SomeProtocol2 {
        // 结构体定义
    }
    
    // 类实现协议和继承父类,协议一般都写在父类后面
    class SomeSuperclass {
        // 父类定义
    }
    
    class SomeClass :SomeSuperclass,SomeProtocol,SomeProtocol2 {
        // 子类定义
    }

    2、协议的属性

    协议不指定是否该属性应该是一个存储属性或者计算属性,它只指定所需的属性名称和读写类型。属性要求总是声明为变量属性,用var关键字做前缀。

    protocol ClassProtocol {
        static var present:Bool { get set }    // 要求该属性可读可写,并且是静态的
        var subject :String { get }            // 要求该属性可读
        var stname :String { get set }         // 要求该属性可读可写
    }
    
    // 定义类来实现协议
    class MyClass :ClassProtocol {
        static var present = false       // 如果没有实现协议的属性要求,会直接报错
        var subject = "Swift Protocols"  // 该属性设置为可读可写,也是满足协议要求的
        var stname = "Class"
    
        func attendance() -> String {
            return "The \(self.stname) has secured 99% attendance"
        }
    
        func markSScured() -> String {
            return "\(self.stname) has \(self.subject)"
        }
    }
    
    // 创建对象
    var classa = MyClass()
    print(classa.attendance())     // 结果:The Class has secured 99% attendance
    print(classa.markSScured())    // 结果:Class has Swift Protocols

    3、协议普通方法实现

    协议可以要求指定实例方法和类型方法被一致的类型实现。这些方法被写为协议定义的一部分,跟普通实例和类型方法完全一样,但是没有大括号或方法体。可变参数是允许的,普通方法也遵循同样的规则,不过不允许给协议方法参数指定默认值。

    // 定义协议,指定方法要求
    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) % m)
            return lastRandom / m
        }
    }
    
    let generator = LinearCongruentialGenerator()
    print("随机数:\(generator.random())")          //结果:随机数: 0.37464991998171
    print("另一个随机数:\(generator.random())")     //结果:另一个随机数: 0.729023776863283

    4、协议中实现构造函数

    协议SomeProtocol中不光可以声明方法/属性/下标,还可以声明构造器,但在Swift中,除了某些特殊情况外,构造器是不被子类继承的,所以SomeClass中虽然能够保证定义了协议要求的构造器,但不能保证SomeClass的子类中也定义了协议要求的构造器。所以我们需要在实现协议要求的构造器时,使用required关键字确保SomeClass的子类必须也得实现这个构造器。

    protocol TcpProtocol {
        // 初始化构造器要求
        init(aprot :Int)
    }
    
    class TcpClass :TcpProtocol {
        var aprot: Int
        // 实现协议的初始化要求时,必须使用required关键字确保子类必须也得实现这个构造器
        required init(aprot: Int) {
            self.aprot = aprot
        }
    }
    
    var tcp = TcpClass(aprot: 20)
    print(tcp.aprot)   // return:20

    三、 使用实例

    开头说的宠物猫和宠物狗的例子,利用协议可以这样实现,声名个动物的父类,然后让猫和狗class都继承与动物class。在定义一个宠物的属性,里面有玩耍和喂食两个方法,让猫和狗都继承与宠物协议,实现代码如下:

    protocol Pet {
        func playWith()
        func fed(food : String)
    
    }
    
    class Animal{
    
    
        var name : String = ""
        var birthPlace : String = ""
    
        init(name: String,birthPlace:String) {
    
            self.name = name
            self.birthPlace = birthPlace
        }
    }
    
    
    class Dog: Animal, Pet{
    
        func playWith() {
    
            print("狗狗在玩")
        }
    
        func fed(food: String) {
    
            if food == "骨头" {
    
                print("狗狗Happy")
            }
            else {
    
                print("狗狗Sad")
            }
        }
    
    
    }
    
    class Cat: Animal, Pet {
    
        func playWith() {
    
    
            print("猫猫在玩")
        }
    
        func fed(food: String) {
    
            if food == "鱼" {
    
                print("猫猫Happy")
            }
            else {
    
                print("猫猫Sad")
            }
        }
    }
    
    
    let dog = Dog(name:"狗狗小黑", birthPlace: "北京")
    
    dog.playWith()
    
    dog.fed(food:"骨头")
    
    let cat = Cat(name:"猫猫小白", birthPlace:"上海")
    
    cat.playWith()
    
    cat.fed(food: "鱼")

    注意:同时继承父类和协议的时候,父类要写在前面

    四、typealias与协议结合的使用

    typealias 的作用是给类型进行扩展,它与协议放在一起使用会碰撞出不一样的火花

    1、typealias的基本使用

    extension Double {
    
        var km : Length{ return self * 1000.0 }
    
        var m : Length{ return self }
    
        var cm : Length{ return self / 100 }
    
    
    }

    这里对Double类型进行扩展

    let runDistance:Length = 3.14.km //3140

    2、typealias结合协议使用

    定义一个协议,代表重量,但是它的类型要根据继承与它的类或结构体来定义,协议代码如下:

    protocol WeightCalculable {
    
        associatedtype WeightType
    
        var weight:WeightType{get}
    
    }

    这里weight属性的类型就抛了出来,便于继承协议的类或结构体来定义

    class iPhone7 : WeightCalculable {
    
        typealias WeightType = Double
    
        var weight: WeightType {
    
            return 0.114
        }
    
    }
    
    class Ship : WeightCalculable {
    
        typealias WeightType = Int
    
        let weight: WeightType
    
        init(weight: Int) {
    
            self.weight = weight
        }
    
    
    }

    这里定义了两个类,一个是iPhone7,一个是Ship,都继承于协议WeightCalculable,但是weight的类型大不相同。
    iPhone7的weight属性是Double类型的,Ship的weight属性是Int类型的。

    extension Int {
    
        typealias Weight = Int
        var t:Weight  {
            return 1_000*self
        }
    
    
    }
    
    let ship = Ship(weight:4_637.t)

    最后这段代码,用于扩充Int类型,自定义了t字段来代表吨

    五、系统协议的使用

    我们还可以继承于系统协议来定义系统方法,这里简单极少介绍三种常用系统协议

    1、Equatable协议用于自定义”==”来实现操作

    class Person:Equatable , Comparable, CustomStringConvertible {
    
        var name:String
        var age:Int
    
        init(name:String,age:Int) {
    
            self.name = name
            self.age = age
        }
    
        var description: String {
    
            return"name: "+name + ",age:" + String(age)
        }
    
    }
    
    func == (left: Person, right: Person) ->Bool{
    
        return left.name == right.name && left.age == right.age
    
    }
    
    let personA = Person(name:"a",age:9)
    
    let personB = Person(name:"a",age:10)
    
    personA == personB
    
    personA != personB

    注意:func == 方法要紧跟协议下面写,否则编译器会报错

    2、Comparable协议用于自定义比较符号来使用的

    func <(left: Person, right: Person) ->Bool{
    
    
            return left.age < right.age
    
    }
    
    let personA = Person(name:"a",age:9)
    
    let personB = Person(name:"a",age:10)

    注意,在定义比较符号后,很多方法也会同时修改便于我们使用,例如排序方法

    let person1 = Person(name:"a",age:9)
    
    let person2 = Person(name:"a",age:12)
    
    let person3 = Person(name:"a",age:11)
    
    var  arrPerson = [person1,person2,person3]
    
    arrPerson .sort()
    
    //此时arrPerson : [person1,person3,person2]

    3、CustomStringConvertible协议用于自定义打印

    class Person:Equatable , Comparable, CustomStringConvertible {
    
        var name:String
        var age:Int
    
        init(name:String,age:Int) {
    
            self.name = name
            self.age = age
        }
    
        var description: String {
    
            return"name: "+name + ",age:" + String(age)
        }
    
    }

    重写description 讲自定义打印格式return出来

    print(person1)
    
    //name: a,age:9

    协议是swift非常重要的一部分,苹果甚至为了它单独出来——–面向协议编程,利用协议的优点和灵活性可以使整个项目结构更加灵活,拥有更加易于延展的架构。

    展开全文
  • Swift 协议

    2015-10-08 16:49:13
    Protocol(协议)用于统一方法和属性的名称,而不实现任何功能。协议能够被类,枚举,结 构体实现,满足协议要求的类,枚举,结构体被称为协议的遵循者。遵循者需要提供协议指定的成员,如属性,方法,操作符,下标等。协议语法...

    Protocol(协议)用于统一方法和属性的名称,而不实现任何功能。协议能够被类,枚举,结 构体实现,满足协议要求的类,枚举,结构体被称为协议的遵循者。遵循者需要提供协议指定的成员,如属性,方法,操作符,下标等。

    协议语法:

    protocol ProtocolTest{
    //协议内容
    }

    在类,结构体,枚举的名称后加上协议名称,中间以冒号:分隔即可实现协议;实现多个协议,协议之间用逗号分开。

    class Pro : ProtocolTest,ProtocolTest
    {

    }

    当某个类含有父类的同时并实现了协议,应当把父类放在所有的协议之前

    class Pro : 父类,协议1,协议2
    {

    }
    协议设置属性声明为变量,在属性后面加上{get set} 表示属性可以读写

    Protocol ProTest{
    var field1: Int{ get set}
    var field2:Int{ get}
    }

    展开全文
  • Swift协议

    千次阅读 2017-05-07 22:08:24
    前言如果你之前使用objective-c编写iOS程序肯定对协议都不陌生,在Swift中苹果将protocol这种语法发扬的更加深入和彻底。Swift中的protocol不仅能定义方法还能定义属性,配合extension扩展的使用还能提供一些方法的...
  • swift协议使用整理

    2018-07-31 10:22:27
    协议能够被类,枚举,结构体实现,满足协议要求的类,枚举,结构体被称为协议的实现者。 实现者需要提供协议指定的成员,如属性,方法,操作符,下标等。 简单使用 1、 声明 public protocol HumanProtocol...
  • Swift 协议的使用

    2017-03-10 13:22:46
    Swift 协议的使用
  • s3协议和swift协议I have explained it from beginner to intermediate level, with code examples and snapshots. ???? 我已经从初学者到中级级别解释了它,并提供了代码示例和快照。 ???? With a protocol, you ...
  • Swift 协议代理的使用和传值

    千次阅读 2016-04-28 22:10:44
    Swift 协议代理的使用和OC的使用步骤是一致.效果图具体使用步骤在SecondViewController里面声明一个协议 1.声明一个协议方法/** * 声明一个协议 */ protocol SecondViewControllerDelegate{ // 协议方法 func ...
  • Swift文件中写好协议2.oc类文件中导入:"项目名-swift.h"格式的文件 即:#include "项目名-swift.h"3.在协议前面添加 @objc例如:@objc protocol MYProtocol {func MyFunc( )}...
  • Swift 协议(Protocols)

    千次阅读 2017-06-26 22:31:32
    协议定义了一个蓝图,规定了用来实现某一特定工作或者功能所必需的方法和属性。类,结构体或枚举类型都可以遵循协议,并提供具体实现来完成协议定义的方法和功能。任意能够满足协议要求的类型被称为遵循(conform)这...
  • swift协议方法实现In this article, we’ll learn about two ways to make protocol methods optional. We’ll explore the advantages and disadvantages of each approach. 在本文中,我们将学习使协议方法成为可...
  • Swift 协议(十八)

    千次阅读 2014-06-20 17:29:15
    协议 (Protocols) 用于统一方法和属性的名称,而不实现任何功能,能够被类、枚举、结构体实现,满足协议要求的都成为协议的遵循者,遵循者需要提供协议指定的成员,如方法,属性,操作符,下标。 1.语法 ...
  • Is it possible in Swift? 在Swift中有可能吗? If not then is there a workaround to do it? 如果没有,那么是否有解决方法?
  • swift 协议

    2015-11-09 12:13:46
    Swift中的协议 在object-c也称之为协议,但是在其他语言中可能被称之为接口Interface(比如说java中)还有可能被称之为纯虚函数。实际上都是一个意思。 协议主要用来规定统一的方法和属性名称,但是不实现任何功能...
  • Swift面向协议编程(附代码)

    千次阅读 2017-02-16 14:20:47
    什么是swift协议?Protocol Swift标准库中有50多个复杂不一的协议,几乎所有的实际类型都是妈祖若干协议的。protocol是Swift语言的底座,语言的其他部分正是在这个底座上组织和建立起来的。这和我们熟知的面向对象...
  • SWIFT协议研究一、SWIFT简介

    千次阅读 2004-09-23 15:34:00
    目前,全世界已有超过200个国家的7000多个银行在使用SWIFT 协议。 环球同业银行金融电讯协会成立于1973 年,是行业认可的合作组织,它主要掌控着银行、经纪人/经销商,投资管理人等机构使用的消
  • 掌握Swift协议 用日常术语来说,我们谈论的协议是指用于控制事件的设置过程或规则系统。每当您启动一个event时,都需要遵守协议。 综合定义 swift协议与event协议没有什么不同, 让我们解开定义语句的关键元素,看...
  • Swift协议(Protocols)

    2015-11-02 15:27:30
    协议主要为一个特定的任务和功能定义一个方法、属性和其他要求,你也可以理解协议就是一种要遵循的规范。学过设计模式的,都知道工厂模式,如果你不知道可以查阅我的博文《23设计模式之工厂方法(FactoryMethod)》,...
1 2 3 4 5 ... 20
收藏数 25,907
精华内容 10,362
关键字:

swift 协议