swift3 协议

2017-04-21 11:39:23来源:CSDN作者:shenhaifeiniao人点击

协议定义了一个方法的蓝图,属性和其他适合特定任务或功能的要求。协议实际上并不提供一个这些要求的实现,它只是描述了一个实现会是什么样子。协议可以通过一个类,结构或枚举提供这些要求的具体实现。满足要求的任何类型的协议都是符合协议。

协议可以要求符合类型有特定的实例属性,实例方法,类型丰富,操作符和下标。

1. 协议的语法

协议名放在类型名之后,用冒号分割,当作定义的一部分。可以列出多个协议,由逗号分隔。
如果一个类有父类,在任何协议之前列出父类名,后跟一个逗号。

protocol FirstProtocol {    // protocol definition goes here}protocol AnotherProtocol {    // protocol definition goes here}class SomeSuperclass{}class SomeClass: SomeSuperclass, FirstProtocol, AnotherProtocol {    // protocol definition goes here}

2. 属性要求

属性要求总是声明为变量属性,用var关键字做前缀。可获取和可设置属性是通过在他们类型声明后编写{ get set }方法,并且可获取属性是通过编写{ get }方法。
协议例子如下:

protocol ExampleProtocol {    var simpleDescription: String { get }    //在协议中定义方法时需要注意,类中的方法因为本身就可以改变类不需要mutating关键字修饰,但是结构struct和枚举enum使用协议时,协议和struct,enum都需要在定义和使用方法前用mutating关键字修饰    mutating func adjust()}

2.1 结构struct使用协议

//结构体使用协议struct SimpleStructure: ExampleProtocol {    var simpleDescription: String = "A simple "    mutating func adjust() {        simpleDescription += "struct."    }}var b = SimpleStructure()b.adjust()let bDescription = b.simpleDescriptionprint(bDescription) //"A simple struct./n"//结构体重的方法如果需要改变结构体本身 使用的方法需要使用mutating进行修饰,如果说我们在上面的adjust中不对结构体做任何修改的话,比如说单纯的打印一段文字,不加mutating也是可以的。

2.2 类class使用协议

//类使用协议class SimpleClass: ExampleProtocol {    //如果在编译时不满足协议要求,Swift会报错    var simpleDescription: String = "A simple "    var anotherProperty: Int = 69105    func adjust() {        simpleDescription += "class."    }}var a = SimpleClass()a.adjust()let aDescription = a.simpleDescriptionprint(aDescription) //"A simple class./n"//类中的方法因为本身就可以改变类所以adjust方法不需要mutating关键字修饰

2.3 枚举enum使用协议

//枚举使用协议enum SimpleEnum:ExampleProtocol {    case out    mutating func adjust() {        print(self.simpleDescription + "enum.")    }    var simpleDescription: String{        get {            switch self {            case .out:                return "A simple "            }        }    }}var c = SimpleEnum.outc.adjust()//输出:A simple enum.

3. 方法要求

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

注意:协议为普通方法使用相同的语法,但不允许给方法参数指定默认值。

3.1 方法协议

方法协议: 定义时没有花括号执行体. 实现仅要求名称相同.

//协议内定义方法使用static进行定义,但是在实现时还是按照上面的规则:在struct或enum中仍然使用static。在class里使用class关键字时表示可override的类型方法实现,而在class里使用static关键字时表示不可override的类型方法实现protocol MyProtocol {    static func foo() -> String}struct MyStruct: MyProtocol {    static func foo() -> String {        return "MyStruct"    }}enum MyEnum: MyProtocol {    static func foo() -> String {        return "MyEnum"    }}class MyClass: MyProtocol {    class func foo() -> String {        return "MyClass,可override的类型方法实现"    }}class MyClass1: MyProtocol {    static func foo() -> String {        return "MyClass,不可override的类型方法实现"    }}

3.2 构造方法协议

构造方法协议: 可以要求遵从者实现指定的构造方法.

实现时用 required init(编译器会自动提示添加)

//必须实现,实现时用 required init(编译器会自动提示添加)protocol 带参数的构造方法协议 {    init(某参数: Int)}class 某类: 带参数的构造方法协议 {    required init(某参数: Int) {     }}protocol 构造方法协议 {    init()}class 某类1: 构造方法协议 {    required init() {    }}

如果子类与父类同时遵从某构造方法协议, 则子类构造方法须加override required

protocol 构造方法协议 {    init()}class 父类 {    init() {    }}class 子类: 父类, 构造方法协议 {    override required init() {    }}

4. 协议扩展

协议扩展: 即使无源码权限下,给已有的类添加协议.

//1.既存实例会自动遵从添加了的协议.protocol ProtocolForInt {    var description:String {get}    mutating func addOne()}extension Int:ProtocolForInt {    mutating func addOne() {        self += 1    }    var description: String {        return "This number is /(self)"    }}var abc:Int = 4abc.addOne()    //5print(abc.description)  //"This number is 5/n"//2.如果一个类型预遵从了协议, 可以直接扩展协议struct MyText {    var text: String    //注意:即使满足了协议要求,类型也不会自动转变,必须为它做出明显的协议声明。    var description: String {        return  "我的自定义显示:" + text    }}//CustomStringConvertible协议内含有必须实现的var description: String参数的可获取方法extension MyText: CustomStringConvertible {}//协议扩展let text1 = MyText(text: "3天学会Swift 3")print(text1)/* 协议扩展时text1输出为"我的自定义显示:3天学会Swift 3/n" 屏蔽上面的协议扩展则text1输出为"MyText(text: "3天学会Swift 3")/n"*/

5. 协议的继承

协议能够继承一到多个协议。语法与类继承基本相同。

protocol InheritingProtocol: SomeProtocol, AnotherProtocol {}

6. 协议实现

6.1 协议的默认实现

//自定义一个可打印和可预览协议//CustomStringConvertible协议需满足var description: String要求//CustomPlaygroundQuickLookable协议需满足var customPlaygroundQuickLook: PlaygroundQuickLook要求protocol MyPrintable: CustomStringConvertible, CustomPlaygroundQuickLookable {}//提供默认实现: 可以给协议扩展提供一个默认的实现, 任何遵从此协议的类型都会获得.extension MyPrintable {    var description: String {        return "控制台: 默认描述"    }    var customPlaygroundQuickLook: PlaygroundQuickLook {        return PlaygroundQuickLook.text("playgroud预览: 默认值")//        return PlaygroundQuickLook.color(UIColor.blue)    }}//1.采用默认实现struct MyText {    var text: String}//MyText采用默认实现extension MyText: MyPrintable {}let text1 = MyText(text: "abcd")    //"控制台: 默认描述/n"print(text1)    //"控制台: 默认描述/n"//2.不采用默认实现struct MyText1 {    var text: String}//MyText1不采用默认实现extension MyText1: MyPrintable {    var description: String {        return "print时的预览:" + self.text    }    var customPlaygroundQuickLook: PlaygroundQuickLook {        return PlaygroundQuickLook.text("我的Text快速预览:" + self.text)    }}let text2 = MyText1(text: "efg")    //"我的Text快速预览:efg"print(text2)    //"print时的预览:efg/n"

6.2 协议中的必需实现和可选实现方法

//协议扩展//swift 中可选协议方法的实现protocol SwiftDiagonProtocol{    //必须    func requiredMethod()    //可选    func optionalMethod()}//方法1:空实现(方法2:将可选实现和必需实现分为2个协议)extension SwiftDiagonProtocol{    func optionalMethod(){        //空实现也可以    }}class SwiftClass: SwiftDiagonProtocol{    func requiredMethod() {        //Someting    }    //如果需要实现可选方法则实现,这里的实现会覆盖extension中的默认实现    func optionalMethod(){        //Something    }}

7. 类专用协议

可以在协议的继承列表中,通过添加关键字『class』,限制协议只能适配到类(class)型,结构和枚举不能遵循该协议。

protocol 一个协议: class, CustomPlaygroundQuickLookable {}class  myText {    var text = "22"}extension myText: 一个协议{    var customPlaygroundQuickLook: PlaygroundQuickLook {        return PlaygroundQuickLook.text(self.text)    }}let text = myText() //22text.text   //22text.customPlaygroundQuickLook  //text("22")print(text) //输出"myText/n",text本身仍然是myText类

8. 协议组合

协议组合: 多个协议临时组合在一起的类型. 形式: 协议1 & 协议2 & …>

protocol 年龄协议 {    var 年龄 : Int { get }}protocol 姓名协议 {    var 姓名: String { get }}struct  学生: 年龄协议, 姓名协议, CustomPlaygroundQuickLookable {    var 年龄: Int    var 姓名: String    var customPlaygroundQuickLook: PlaygroundQuickLook {        return PlaygroundQuickLook.text(self.姓名 + ":/(self.年龄)岁")    }}//无论传递的寿星是何类型,只要遵从年龄和姓名协议即可,参数大大自由化.func 生日祝愿(寿星: 年龄协议 & 姓名协议)  {    print("祝",寿星.姓名,寿星.年龄,"岁生日快乐!")}let 学生1 = 学生(年龄: 20, 姓名: "洪荒少女")    //"洪荒少女:20岁"生日祝愿(寿星: 学生1)   //输出:祝 洪荒少女 20 岁生日快乐!

9. 协议的检查和转换

9.1 协议的检查 is

struct Person: OneProtocol {}let p1 = Person()if (p1 is OneProtocol){ //可以理解为:p1 是一个遵守了OneProtocol协议类型的实例    print("yes")}//输出:yes

9.2 协议的转换 as

protocol Coder {    var name :String {get set}    var updating: String { get }}struct AndroidCoder: Coder {    var name: String    var updating: String {        return "安卓程序员学iOS开发"    }}struct DotNotCoder: Coder {    var name: String    var updating: String {        return ".NET程序员学Swift 3"    }}struct NewBie {    var name: String}let a = AndroidCoder(name: "小米")let d = DotNotCoder(name: "小猫")let x = NewBie(name: "小狗")let coders:[Any] = [a,d,x]for coder in coders {    //as操作符用来把某个实例转型为另外的类型,由于实例转型可能失败,因此Swift为as操作符提供了两种形式:选项形式as?和强制形式as!    //as? 如果转换不成功的时候便会返回一个 nil 对象,如果能确保100%会成功的转换则可使用 as!,否则使用 as?    //as!由于是强制类型转换,如果转换失败会报 runtime 运行错误。    if let coder1 = coder as? Coder {        print(coder1.updating)    } else {        print("你不是程序员!你会很辛苦的!")    }    if let xiaobo = coder as? NewBie {        print("你是"+xiaobo.name)    }}/*输出:安卓程序员学iOS开发.NET程序员学Swift 3你不是程序员!你会很辛苦的!你是小狗*/

10. 类型约束

func findIndex<T: Equatable>(array: [T], valueToFind: T) -> Int? {    var index: Int?    for (i, value) in array.enumerated() {        if (value == valueToFind) {            index = i        }    }    return index}var testArray = [1, 2, 3, 4]findIndex(array: testArray, valueToFind: 3) //2//swift标准库定义了一个Equatable协议,该协议要求任何遵循该协议的类型实现(==)和(!=)对任何两个该类型进行比较。所有的swift标准类型自动支持Equatable协议。

11. 其他

类中在协议中没有定义的属性,我们是无法访问的

protocol ProtocolForInt {    var description:String {get}    mutating func addOne()}class SimpleClassForInt:ProtocolForInt {    var number = 0    var description: String = "这是一个描述"    func addOne() {        number += 1    }}var simpleClassForInt:ProtocolForInt = SimpleClassForInt()print(simpleClassForInt.description)    //"这是一个描述/n"simpleClassForInt.addOne()simpleClassForInt   //number:1,description:"这是一个描述"//print(simpleClassForInt.number) //错误,类中在协议中没有定义的属性,无法访问

我们可以看到只有协议中定义的属性和方法是我们可以访问的,类中在协议中没有定义的属性,我们是无法访问的。
尽管simpleClassForInt的运行时(Runtime)类型是SimpleClassForInt,但是编译器还是会把它视为ProtocolForInt类型,所以在协议之外的属性和方法在simpleClassForInt中是无法访问的。

参考自
SwiftV课堂视频源码
http://c.biancheng.net/cpp/html/2433.html
http://www.wendq.com/wd/201702/14136.html
http://www.jianshu.com/p/09d312dac288
http://blog.csdn.net/anan890624/article/details/52645176

最新文章

123

最新摄影

微信扫一扫

第七城市微信公众平台