Swift学习之协议三

面向协议编程 (Protocol Oriented Programming,以下简称 POP) 是 Apple 在 2015 年 WWDC 上提出的 Swift 的一种编程范式。相比与传统的面向对象编程 (OOP),POP 显得更加灵活。

  • 如何将BVC和DVC的公共方法 testMethod抽取出来
class BVC: UIViewController
{
    func testMethod() {
        print("测试方法")
    }
}

class DVC:UITableViewController{
    func testMethod() {
        print("测试方法")
    }
}

一、OOP解决方案

1、用新的类型来提供这个功能
class testTool{
    func testMethod() {
        print("测试方法")
    }
    
}

class ViewCotroller: UIViewController
{
    var testtool:testTool?
    override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
        self.testtool = testTool()
        self.testtool?.testMethod()
    }
}


class tableViewContoller:UITableViewController{
    var testtool:testTool?
    override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
     self.testtool = testTool()
     self.testtool?.testMethod()
    }
}
  • 依赖注入引入额外的依赖关系,可能也是我们不太愿意看到的。
2、UIViewController 上添加 extension
extension UIViewController{
    func testMethod() {
        print("测试方法")
    }
}
let v = ViewCotroller()
v.testMethod()

let t = tableViewContoller()
t.testMethod()
  • 看起来这是一个稍微靠谱的做法,但是给任何UIViewController类都添加了testMethod,这种添加代码影响也是不可估计 的,不想看到的。

二、POP解决方案

import UIKit

protocol test{

   func testMethod()
}


extension test{

    func testMethod(){
        print("测试方法")
    }
    
}


class ViewCotroller: UIViewController,test
{
  
}


class tableViewContoller:UITableViewController,test{

}

let  v = ViewCotroller()

let  t = tableViewContoller()

v.testMethod()
t.testMethod()
  • 通过易个协议扩展,我们只需要简单地声明 ViewController 和 tableViewContoller 遵守 test,就可以直接使用 testMethod 的实现了:

三、POP的应用

使用注意点:

  • 1、 优先考虑创建协议,而不是父类(基类)
  • 2、优先考虑值类型(struct、enum),而不是引用类型(class)
  • 3、巧用协议的扩展功能
  • 4、不要为了面向协议而使用协议。

四、优雅的前缀

如果我们设计一个可以计算字符串长度的方法

4.1、直接扩展一个方法

extension String{
    func numberCount() -> Int {
        return self.count
    }
}
print(string.numberCount())

4.2、扩展一个计算属性

extension String{
    var mj_numberCount :Int{
        return self.count
    }
}
print(string.mj_numberCount)

4.3、加一个前缀避免和系统方法冲突

struct Mj {
    var string:String
    init(_ str:String) {
        self.string = str
    }
    var numberCount :Int{
        return self.string.count
    }
}
extension String{
    var mj:Mj{return Mj(self)}
}
print(string.mj.numberCount)
struct Mj<Base>{
    var base:Base
    
    init(_ base:Base) {
        self.base = base;
    }
   
}
extension String{
    var mj:Mj<Self>{return Mj(self)}
}

extension Int{
    var mj:Mj<Self>{return Mj(self)}
}


extension Mj where Base == String{
    var numbercount :Int{
        return self.base.count
    }
}

extension Mj where Base == Int{
    var  floatcount :Float{
        return Float(self.base)
    }
}


var string = "测试"
print(string.mj.numbercount)

var a = 10
print(a.mj.floatcount)

4.4、使用协议优雅的添加一个前缀



struct Mj<Base>{
    var base:Base
    
    init(_ base:Base) {
        self.base = base;
    }
   
}

protocol MJCompatable{}


extension MJCompatable{
    var mj:Mj<Self>{
        get {Mj(self)}
        set{}
    }
}


extension String:MJCompatable{}


extension Mj where Base == String{
    var numbercount :Int{
        return self.base.count
    }
}


extension Int:MJCompatable{}

extension Mj where Base == Int{
    var  floatcount :Float{
        return Float(self.base)
    }
}


var string = "测试"
print(string.mj.numbercount)

var a = 10
print(a.mj.floatcount)

五、使用协议实现类型判断

判断一个是否为一个数组

func isArray(_ value: Any)  -> Bool {
    value is [Any]
}
print(isArray(NSArray()))
print(isArray([1,"2"]))
print(isArray("123444"))
import Foundation
protocol Arraytype {}
extension Array: Arraytype{}
extension NSArray: Arraytype{}
func isArrayType(_ type: Any.Type) -> Bool {
    type is Arraytype.Type
}
print(isArrayType([Int].self))
print(isArrayType([Any].self))
print(isArrayType(NSArray.self))
isArrayType(NSMutableArray.self)
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。