iOS 相关

swift协议介绍及应用

2021-01-05  本文已影响0人  大宝的爱情

协议规定了用来实现某一特定功能所需的方法和属性。

任意能够满足协议要求的类型被称为遵循(conform)这个协议。

类,结构体或枚举类型都可以遵循协议,并提供具体实现来完成协议定义的方法和功能。

1,语法及相关定义

协议的语法格式如下:

protocol SomeProtocol {
    // 协议内容
}

要使类遵循某个协议,需要在类型名称后加上协议名称,中间以冒号:分隔,作为类型定义的一部分。遵循多个协议时,各协议之间用逗号,分隔。

struct SomeStructure: FirstProtocol, AnotherProtocol {
    // 结构体内容
}

如果类在遵循协议的同时拥有父类,应该将父类名放在协议名之前,以逗号分隔。

class SomeClass: SomeSuperClass, FirstProtocol, AnotherProtocol {
    // 类的内容
}

2,对属性和方法的规定

属性方法:

协议用于指定特定的实例属性或类属性,而不用指定是存储型属性或计算型属性。此外还必须指明是只读的还是可读可写的。

协议中的通常用var来声明变量属性,在类型声明后加上{ set get }来表示属性是可读可写的,只读属性则用{ get }来表示。

protocol Person {
    //读写属性
    var name:String{get set}
     
    //只读属性
    var age:Int{get}
     
    //类型方法:加static关键字,类似类方法
    static func method1()
     
    //实例方法:用于类遵守协议时
    func method2() -> Int
     
    //突变方法:针对枚举结构体遵守协议时加mutating关键字
    mutating func method3()
}

方法规定:

在Swift中,class(类)、struct(结构体)、enum(枚举)都能有协议
但是协议中有个关键字mutating,协议所针对类型不同,对这个关键字的需求也就不同

关键字mutating允许在实例方法中修改对象本身或属性的值(通结构体改变自身成员变量需加mutating一致)

理解:Swift中有三种type(类型):class(类),struct(结构体),enum(枚举)
这三个类型的区别在于class是引用类型,而另外两个是值类型。区别在于,引用类型的对象是可以动态分配的(可以变化),而值类型的对象在初始化时一般就分配好了(不准改动)。而mutating关键字则允许在它修饰的方法中去修改对象本身的值或对象属性的值(self或self.xxx的值)
上述对于mutating关键字的原理解释,如依然不懂就记住:
1.如果协议仅针对class,不需要mutating关键字
2.如果协议会被enum或struct使用,协议中的方法需要mutating修饰

2,协议和拓展的结合

通过扩展采纳协议

不论是否能够访问一个已有类型的源代码,都可以通过扩展使该类型采纳或实现某个协议,以增加该类型的功能。

protocol Name{
    var name: String{get}
}

class Animal{
    var legs:Int = 4
}

extension Animal : Name{
    var name: String{
        return "Animal"
    }
}

let ani = Animal()
print(ani.name)    //输出Animal

当一个类型符合了某个协议的所有要求,确还没有声明采纳该协议,类型并不会自动采纳协议,此时可以通过一个空扩展来采纳协议。

eg. extension Animal:Name{}

实际应用:tableview的dataSource和delegate,一般对控制器进行拓展实现其必须方法,使代码结构更加整洁,可读性更强

协议扩展

协议可以通过扩展来为采纳协议的类型提供属性、方法及下表脚本的实现。这样可以基于协议本身来实现这些功能,而无需在每个采纳协议的类型中都重复同样的实现。很强大

protocol Animal{
    var name:String{get set}
}

extension Animal{
    func run(){
        print("I am running")
    }
}

class Dog : Animal{
    var name:String = "Animal"
}

let dog = Dog()
dog.run()    //输出 I am running

3,可选协议实现

原生的 Swift protocol 里没有可选项,所有定义的方法都是必须实现的。
给自定义的协议中添加extension,在extension中对可选方法进行默认实现,这样遵守协议的对象就可以不用实现可选方法.
示例:

protocol OptionalProtocol {
    func optionalMethod()        // 可选
    func necessaryMethod()       // 必须
    func anotherOptionalMethod() // 可选
}

extension OptionalProtocol {
    func optionalMethod() {
        print("Implemented in extension")
    }

    func anotherOptionalMethod() {
        print("Implemented in extension")
    }
}

class MyClass: OptionalProtocol {
    func necessaryMethod() {
        print("Implemented in Class3")
    }

    func optionalMethod() {
        print("Implemented in Class3")
    }
}

let obj = MyClass()
obj.necessaryMethod() // Implemented in Class3
obj.optionalMethod()  // Implemented in Class3
obj.anotherOptionalMethod() // Implemented in extension

注意:(纯swift可以忽略下边话和代码)
如果考虑到Swift与Objective-C混编,或者,所写的协议要支持Objective-C(可能是用Swift写的一个开源组件,同时支持Objective-C),那么Objective-C代码中的对象想要遵守Swift中自定义的协议,那么使用@objc关键字实现协议的可选方法是更好的选择

如果自定义了拦截器作为代理,实现了以下两个运行时方法,那么就不能使用协议的分类实现协议的可选方法,因为拦截器可能会优先选择分类的实现,而控制器作为代理,被作为第二选择,代码示例如下:

internal override func forwardingTarget(for aSelector: Selector) -> Any? {
    if pickerView!.responds(to: aSelector) {
        return pickerView
    } else if delegate != nil && delegate!.responds(to: aSelector) {
        return delegate
    } else {
        return nil
    }
}

internal override func responds(to aSelector: Selector) -> Bool {
    if pickerView!.responds(to: aSelector) {
        return true
    } else if delegate != nil && delegate!.responds(to: aSelector) {
        return true
    } else {
        return super.responds(to: aSelector)
    }
}

4,实际应用

①延迟方法举例:

protocol AfterDelayToDo {
    func afterTimeToDo(_ time: CGFloat, todo:@escaping () -> Void)
}

extension AfterDelayToDo {
    func afterTimeToDo(_ time: CGFloat, todo:@escaping () -> Void) {
        DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + TimeInterval(time)) {
            todo()
        }
    }
}
应用:在需要的控制器遵守AfterDelayToDo,
调用:在方法内部直接写
 afterTimeToDo(1) {
    //一秒后执行            
 }

②:系统弹窗封装

protocol SystemAlertViewProtocol {
    func showSystemAlertInView(_ msg: String?, leftTitle: String?, rightTitle: String?, leftAction: (() -> Void)?, rightAction: (() -> Void)?)
}

extension SystemAlertViewProtocol where Self: UIViewController {
    ///系统弹窗
    func showSystemAlertInView(_ msg: String?, leftTitle: String?, rightTitle: String?, leftAction: (() -> Void)?, rightAction: (() -> Void)?) {
        let alert = UIAlertController(title: "提示", message: msg, preferredStyle: .alert)

        if !(leftTitle?.isEmpty ?? true) {
            let action = UIAlertAction(title: leftTitle, style: UIAlertAction.Style.default, handler: { (_) in
                leftAction?()
            })
            alert.addAction(action)
        }
        if !(rightTitle?.isEmpty ?? true) {
            let action = UIAlertAction(title: rightTitle, style: UIAlertAction.Style.default, handler: { (_) in
                rightAction?()
            })
            alert.addAction(action)
        }
        self.present(alert, animated: true, completion: nil)
    }
}
应用:在需要的控制器遵守SystemAlertViewProtocol,
调用:在方法内部直接写:
showSystemAlertInView("提示", leftTitle: "取消", rightTitle: "确定", leftAction: {
    //点击取消按钮点击事件            
}) {
   //点击确定按钮点击事件
}

③:见链接点击跳转

参考:
swift可选协议实现
swift协议和拓展
swift拓展协议组合使用

上一篇下一篇

猜你喜欢

热点阅读