美文网首页
Swift优雅的使用Protocol(二) 从Swift说开去

Swift优雅的使用Protocol(二) 从Swift说开去

作者: seasonZhu | 来源:发表于2018-12-29 17:11 被阅读24次

Swift的Protocol可不仅仅作为OC时代中的代理去运用,当对Swift的Protocol理解足够深的时候,其实对Swift语言有了足够的了解.

我们这次先从一个简单的例子来说明,我们有一个数组,里面一个字符串(String),一个数字(Int)和一个我们自定义的枚举(MyType).

我们都知道,Swift的数组中的元素,必须都是同一种类型,如果我们在一个数组中放入不同类型的时候,我们必须声明这个数组为[Any]类型,否则会报错.

enum MyType {
    case one
    case two
}

let array: [Any] = [1, "string", MyType.one]

那么这个Any是什么呢?

protocol Any { }

Any是一个空协议,并且所有的类型都隐式的遵守了这个协议,所以当我们用[Any]来表示这个数组的时候,是可以的.

以下代码是伪代码,只是为了便于理解

struct String: Any {

}

struct Int: Any {

}

enum MyType: Any {

}

这算是遵守协议呢,还是算继承了协议呢?

从协议Any说完之后,我们有第二个需求了,我希望上面的这个array里面的元素,都进行字符串化,然后获得一个新的数组.MyType的枚举是one -> "1", two -> "2"

let array: [Any] = [1, "string", MyType.one]
var stringArray = [String]()
for obj in array  {
  /*
   用一个方法让obj变为string
   obj -> String
   */
  stringArray.append("加入字符串化的obj")
}

大概就是上面代码的意思,按照一般的逻辑,由于obj已经变成了Any,不再是Int类型,所以我们还需要进行类型转换,还好上面的array数组中只有三个元素,我们可以通过判断来进行类型转换,然后进行元素的字符串化,如果这个数组的元素个数不确定并且类型很多样,这样做真的好吗?

这个是时候协议的作用就体现出来了.

我们先定义一个协议FormatStringPotocol

protocol FormatStringPotocol {
    var toSting: String { get }
}

不要惊讶于Swift的协议可以定义属性,它还可以定义属性的读写性.

我们让Int,String,MyType都去遵守这个协议

extension Int: FormatStringPotocol {
    var toSting: String {
        <#code#>
    }
    
    
}

extension String: FormatStringPotocol {
    var toSting: String {
        <#code#>
    }
    
    
}

extension MyType: FormatStringPotocol {
    var toSting: String {
        <#code#>
    }
    
    
}

那么如何去写这些实现呢?

String(Int)即把Int字符串化,而String本身就是String,不用任何的操作,至于枚举我们可以通过对其本身的switch来获取不同的字符串值.
最后的代码应该是这样的:

extension Int: FormatStringPotocol {
    var toSting: String {
        return String(self)
    }
}

extension String: FormatStringPotocol {
    var toSting: String {
        return self
    }
}

extension MyType: FormatStringPotocol {
    var toSting: String {
        switch self {
        case .one:
            return "1"
        case .two:
            return "2"
        }
    }
}

好了,我们把数组的类型声明稍微改动一下,将Any改为FormatStringPotocol

let array: [FormatStringPotocol] = [1, "string", MyType.one]
var stringArray = [String]()
for obj in array  {
  let string = obj.toSting
  stringArray.append("加入字符串化的obj")
}

这里有一个小小的思维跳跃,既然Any是协议可以在声明数组类型的使用,那么自己定义的协议类型可以使用,另外就是OC到Swift对于Protocol的理解认知的墙,我们在这里既是遵守了FormatStringPotocol协议,也可以说是继承了FormatStringPotocol呀.
而FormatStringPotocol恰好有一个toSting的计算属性,可以让我们做字符串化的工作.

想想看,继续定义了一个新的类型,并将其生成的对象放入数组中想做统一的字符串化处理,那么你只需要遵守这个FormatStringPotocol即可!并行通过这种协议的继承,我们将Int,String,MyType这些毫无关联性的类型统一到了一种类型中,在使用和调用方法的时候,会是多么方便!

Swift是一门面向协议编程的语言,这句话我很早就读到过,但是真正理解,我觉得自己还缺火候.

Protocol是可以理解为遵守,亦可以理解为继承.

在很多知名的Swift框架中,面向协议编程已经成为了主流.

我们举一个简单的例子,Alamofire中URLConvertible协议,这段代码的注释我已经去掉了.


public protocol URLConvertible {

    func asURL() throws -> URL
}

extension String: URLConvertible {

    public func asURL() throws -> URL {
        guard let url = URL(string: self) else { throw AFError.invalidURL(url: self) }
        return url
    }
}

extension URL: URLConvertible {
    public func asURL() throws -> URL { return self }
}

extension URLComponents: URLConvertible {
    public func asURL() throws -> URL {
        guard let url = url else { throw AFError.invalidURL(url: self) }
        return url
    }
}

这个URLConvertible的目的是什么,将String/URL/URLComponents的对象转为URL!
这和我们上面的例子是不是非常相似!?

然后让我们看看使用的时候调用:

@discardableResult
public func request(
    _ url: URLConvertible,
    method: HTTPMethod = .get,
    parameters: Parameters? = nil,
    encoding: ParameterEncoding = URLEncoding.default,
    headers: HTTPHeaders? = nil)
    -> DataRequest

我们经常在使用的就是这样的:

Alamofire.request("字符串网址")

其实传入一个URL或者URLComponents都是可以,因为它们都遵守URLConvertible!

可能有人会说,搞这么复杂干嘛,能传入字符串不就好了吗.
Alamofire这么设计必然有其理由,再来将几种类型通过协议达成统一,也是化繁为简的思路,这里我们不过多的讲Alamofire的用法和思路.

Swift的Protocol,回调只是很少的一部分功能,而这部分功能往往都和cocoa框架有关,而当Protocol跳出来,为enum,struct,class所用的时候,就好比跳出三界看世界一样.
它用来进行有力的类型的内部约束,用来统一Api,用来将非关联的化为统一...

而Protocol真正的魅力所在是它可以extension

protocol FormatStringPotocol {
    var toSting: String { get }
}

extension FormatStringPotocol {
    var toString: String {
        return "FormatStringPotocol"
    }
}

好了,那是下节要说的点.

相关文章

网友评论

      本文标题:Swift优雅的使用Protocol(二) 从Swift说开去

      本文链接:https://www.haomeiwen.com/subject/qlubhqtx.html