加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 百科 > 正文

swift3 协议

发布时间:2020-12-14 06:19:32 所属栏目:百科 来源:网络整理
导读:协议定义了一个方法的蓝图,属性和其他适合特定任务或功能的要求。协议实际上并不提供一个这些要求的实现,它只是描述了一个实现会是什么样子。协议可以通过一个类,结构或枚举提供这些要求的具体实现。满足要求的任何类型的协议都是符合协议。 协议可以要求

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

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

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.simpleDescription
print(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.simpleDescription
print(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.out
c.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 = 4
abc.addOne()    //5
print(abc.description)  //"This number is 5n"

//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 3n" 屏蔽上面的协议扩展则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时的预览:efgn"

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() //22
text.text   //22
text.customPlaygroundQuickLook  //text("22")
print(text) //输出"myTextn",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://www.52php.cn/article/p-azvphnod-qq.html

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读