协议

 

 

/** 协议 **/

 

//// 1.定义协议

 

//格式:协议的定义方式与类, 结构体, 枚举的定义非常相似

protocol SomeProtocol {

    //协议方法

}

 

//协议可以继承一个或者多个协议

protocol SomeProtocol2:SomeProtocol {

    //协议定义

}

 

//结构体实现协议

struct SomeStrure : SomeProtocol,SomeProtocol2 {

    //结构体定义

}

 

//类实现协议和继承父类, 协议一般卸载父类后面

class SomeSuperclass {

    //父类定义

}

class SomeClass: SomeSuperclass, SomeProtocol{

    

    //子类定义

}

 

//// 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 Protocol" //该属性设置为可读可写, 也是满足协议的要求

    var stName: String = "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 Protocol

 

//// 3.协议普通方法实现

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

 

//定义协议, 指定方法要求

protocol RandomNumberGenerator {

    func random() -> Double  //实现该协议, 需要实现该方法

}

 

class LinerCongruentialGenerator : RandomNumberGenerator {

    var lastRandom = 45.0

    let m = 149998.0

    let a = 24489.0

    let c = 29879.0

    

    // 实现协议方法

    func random() -> Double {

        lastRandom = ((lastRandom * a + c).truncatingRemainder(dividingBy: m)) //truncatingRemainder 替代旧方法 %

        return lastRandom / m

    }

}

 

let generator = LinerCongruentialGenerator()

print("随机数:\(generator.random())")    //随机数:0.545993946585954

print("再来随机数:\(generator.random())") //再来随机数:0.0449539327191029

 

 

//// 4.协议中实现构造函数

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

 

protocol TcpProtocol {

    // 初始化构造器要求

    init(aprot:Int)

}

 

class TcpClass: TcpProtocol {

    var aprot: Int

    required init(aprot: Int) {

        self.aprot = aprot

    }

}

 

var tcp = TcpClass(aprot: 20)

print(tcp.aprot)

 

 

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

 

//// 5.使用实例

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

 

protocol Pet {

    func payWith()

    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 payWith() {

        print("🐶在玩耍")

    }

 

    func fed(food: String) {

        if food == "骨头" {

            print("🐶Happy")

        }else{

            print("🐶Sad")

        }

     }

}

 

class Cat: Animal, Pet {

    func fed(food: String) {

        if food == "鱼" {

            print("🐱Happy")

        }else{

            print("🐱Sad")

        }

    }

    func payWith() {

        print("🐱在玩耍")

    }

}

 

let dog = Dog(name: "狗狗小累累", birthPlace: "河南")

dog.payWith()

dog.fed(food: "骨头")

 

let cat = Cat(name: "猫猫小可爱", birthPlace: "北京")

cat.payWith()

cat.fed(food: "鱼")

 

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

 

 

//// 5.typealias与协议结合的使用

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

 

//1.typealias 的基本使用

 

//extension Double {

//    var km : Length {

//        return self * 1000.0

//    }

//    var m : Length {

//        return self;

//    }

//    var cm : Length {

//        return self / 100

//    }

//}

//

//let runDistance:Length = 3.14.km // 3140

 

//2.typealias结合协议使用

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

 

protocol WeightCalculble {

    

    associatedtype WeightType

    

    var weight:WeightType{get}

    

}

 

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

 

class iPhone7 : WeightCalculble {

    

    typealias WeightType = Double

    

    var weight:WeightType{

        

        return 0.1314

    }

}

 

class ship: WeightCalculble {

    

    typealias WeightType = Int

    

    let weight: WeightType

    

    init(weight: Int) {

        

        self.weight = weight

    }

}

 

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

 

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

 

extension Int {

    

    typealias Weight = Int

    

    var t:Weight {

        

        return 1_000 * self

    }

}

 

 

//// 6.协同协议的使用

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

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

 

class Person:Equatable , Comparable, CustomStringConvertible {

    /// Returns a Boolean value indicating whether the value of the first

    /// argument is less than that of the second argument.

    ///

    /// This function is the only requirement of the `Comparable` protocol. The

    /// remainder of the relational operator functions are implemented by the

    /// standard library for any type that conforms to `Comparable`.

    ///

    /// - Parameters:

    ///   - lhs: A value to compare.

    ///   - rhs: Another value to compare.

    static func <(lhs: Person, rhs: Person) -> Bool {

        return false

    }

    

    var name:String

    var age:Int

    

    init(name:String, age:Int) {

        self.name = name

        self.age = age

    }

    

    var description: String {

        return "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: 10)

let personB = Person(name: "b", age: 20)

personA == personB

personA != personB

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

 

 

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

func <(left: Person, right: Person) -> Bool {

    

    return left.age < right.age

}

let personC = Person(name:"c",age:9)

let personD = Person(name:"d",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 PersonClass2:CustomStringConvertible {

    /// Returns a Boolean value indicating whether two values are equal.

    ///

    /// Equality is the inverse of inequality. For any values `a` and `b`,

    /// `a == b` implies that `a != b` is `false`.

    ///

    /// - Parameters:

    ///   - lhs: A value to compare.

    ///   - rhs: Another value to compare.

    static func ==(lhs: PersonClass2, rhs: PersonClass2) -> Bool {

        return false

    }

    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: ,age:9

 

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

 

//// 协议的扩展补充  以下一般不会这么写, 因为没什么意义

protocol ShareString {

    func methodForOverride()

    func methodWithoutOverride()

}

 

extension ShareString {

    func methodForOverride(){

        print("😋")

    }

    func methodWithoutOverride(){

        print("======")

        methodForOverride()

        print("------")

    }

}

extension String:ShareString {

    func methodForOverride() {

        print(self)

    }

}

 

let hello:ShareString = "hello"

hello.methodForOverride()

hello.methodWithoutOverride()

 

posted @ 2017-08-15 14:38  路人Q  阅读(253)  评论(0)    收藏  举报