Swift4.0 擴展協議

在OC里面中,Category大家一定不陌生,他可以很好的為我們服務,給指定的類實現系統(tǒng)不提供的方法。


  • 例子可能不恰當,無關緊要,重點不是OC

比如要實現:把Data轉化為一個UInt8的數組
我們可能會這樣子寫

UInt8 *bytes = (UInt8 *)data.bytes;

現在我們不想像上面那個樣子,強制類型轉換,直接就是UInt8的數組,我們就可以創(chuàng)建一個Category,然后實現方法

.h 
- (UInt8 *)toUInt8;

.m
- (UInt8 *)toUInt8{
   return (UInt8 *)data.bytes;
}

實現了上面的方法之后,到需要的地方引入頭文件就可以實現這樣子調用

UInt8 *bytes = data.toUInt8;

這樣子,我們就可以在實現了對NSData這個類的擴展,并且是無污染的,拖到任何一個工程就可以使用(當然,例子中的命名方式不是很靠譜,這里忽略,重點不是他)。


現在來到Swift中,如果我們也要實現如上的功能,我們可以使用Extension,也可以很方便的完成它。

新建一個Swift文件,然后實現如下代碼:

extension Data {
    func toUInt8() -> [UInt8]{
        var bytes: [UInt8] = [UInt8](repeating: 0, count: count)
        copyBytes(to: &bytes, count: count)
        return bytes
    }
}

調用如下:

let data = Data(bytes: [0,1,2,3,4,5,6,7,8])
print(data.toUInt8())

打印結果:
[0, 1, 2, 3, 4, 5, 6, 7, 8]



假設你現在這個代碼就寫完啦,也沒有問題,可以達到預想的效果了,然后新來的了一個工程師,然后他也需要把Data轉化為[UInt8],但是代碼是你寫的,他并不知道啊。

  • 第一種情況 于是乎他又寫了一個方法UInt8,實現的功能和你的一樣,這樣子就會有兩個功能一樣,只是命名方式不一樣的方法了。
  • 第二種情況 他也寫了一個和你命名方式一樣的方法,但是他也新建了一個文件,然后你們兩個方法就沖突了,他就很納悶,黑人問號???,然后就是一頓查找……
    然后就是隨著你的需求增加,你添加的方法越來越多,當你去了另外一家公司,你的這些成果本來是想著拖進去就用,但是卻有了耦合,這豈不是很尷尬?



所以在Swift有了一種更優(yōu)雅的擴展方法:協議擴展



接下來用一個Demo去實現它,看看他到底有多爽!?。?!

正題開始啦?。。?/h4>




1、 布局UI,并且他事件拖入到ViewController
image.png
2、新建一個Swift文件 PQDataEncodable.swift

這里需要注意的是:
Swift標準庫為我們提供了55中協議,他們的命名方式有著自己規(guī)則,基本是以“Type”、“able'”、“Convertible”結尾,分別代表了“可以被當做XX類型”、“具備某種能力或特性”、“能夠進行改變或者變換”。所以在命名的時候應該盡可能遵守這一套規(guī)則,便于開發(fā)人員之間的高校合作。

image.png

3、創(chuàng)建一個協議,實現它。
  • 3.1 創(chuàng)建一個協議先:
protocol PQDataEncodable {
    /// 關聯類型
    associatedtype WarpperType
    /// 這個就是命名,我這里使用pq,你可以使用你的,比如:SnapKit,他的就是 view.snp.XXXX
    var pq: WarpperType { get }
}
  • 3.2 創(chuàng)建一個結構體,繼承協議
struct ExtensionPQDataEncodable<T>: PQDataEncodable {
    /// T 泛型
    let pq: T
    /// 構造方法
    init(pq: T) {
        self.pq = pq
    }
}
  • 3.3 很重要的一環(huán)來了,為自己的協議添加默認實現方法
/// 這里指定 WrapperType 是 Data,所以在 PQDataEncodable 中的 pq 就是 Data 類型了
extension PQDataEncodable where WarpperType == Data {
    /// 方法名 返回參數
    func toUInt8() -> [UInt8]{
        /// 根據數組長度,創(chuàng)建數組
        var bytes = [UInt8](repeating: 0, count: pq.count)
        /// 把 Data 的 Bytes 拷貝到 數組中
        pq.copyBytes(to: &bytes, count: pq.count)
        /// 返回數組
        return bytes
    }
    
    func toHex() -> String {
        /// 創(chuàng)建一個字符串
        var hex: String = ""
        /// 遍歷數組,在轉換為16進制添加到字符串中
        for i in 0..<toUInt8().count {
            hex.append(NSString(format: "%02x", pq[i]) as String)
            /// 長度為4就添加一個空格, 格式化字符串
            if (i + 1) % 4 == 0 { hex.append(" ") }
        }
        /// 返回字符串
        return hex
    }
}
  • 3.4 最后一步就是,在Data中添加一個結構體,由于這個結構體是繼承我自己的協議的,所以就擁有了我協議里面默認的實現方法。
extension Data {
    var pq: ExtensionPQDataEncodable<Data> {
        return ExtensionPQDataEncodable(pq: self)
    }
}




然后我們就可以在ViewController中這樣子調用了

class ViewController: UIViewController {
    
    let data = Data(bytes: [0x2,0x33,0x54,0x78,0x1,0x2d,0x3a,0x5b])

    @IBAction func toHexBtnClick(_ sender: Any) {
        print(data.pq.toHex())
    }
    @IBAction func toUInt8BtnClick(_ sender: Any) {
        print(data.pq.toUInt8())
    }
    @IBAction func redBtnClick(_ sender: Any) {
    }
    @IBAction func greenBtnClick(_ sender: Any) {
    }
    @IBAction func blueBtnClick(_ sender: Any) {
    }
}

輸出結果如下:

02335478 012d3a5b 012d3a5b 012d3a5b 
[2, 51, 84, 120, 1, 45, 58, 91, 1, 45, 58, 91, 1, 45, 58, 91]


這樣子整個逼格就提高啦,但是你可能會有疑問,為什么要新建一個結構體呢???

我們在UIView的時候不是可以直接指定么?
例如下面的寫法:

import UIKit

protocol TEST where Self : UIView {
    
}

然后我們就嘗試的這樣子寫:

protocol TEST where Self : Data {
    
}
error

我們進入UIView,看看他的定義

NS_CLASS_AVAILABLE_IOS(2_0) @interface UIView : UIResponder <NSCoding, UIAppearance, UIAppearanceContainer, UIDynamicItem, UITraitEnvironment, UICoordinateSpace, UIFocusItem, CALayerDelegate>

在進入Data,看看他的定會

public struct Data : ReferenceConvertible, Equatable, Hashable, RandomAccessCollection, MutableCollection, RangeReplaceableCollection

一個是Class、一個是Struct,所以我們需要一個Struct來繼承協議,不可以直接對原有的struct進行處理。
剛才分析到Class就可以這樣子搞,那么也就是說這個Struct也可以是一個Class,然后我們就來實驗一下。

4、新建一個協議 PQColorable.swift然后實現如下代碼
/// 新建一個協議
protocol PQColorable {
    /// 關聯類型
    associatedtype WarpperType
    var pq: WarpperType { get }
}

/// 定義一個類
final class ExtensionPQColorable<T>: PQColorable {
    /// 泛型
    let pq: T
    /// 構造方法
    init(pq: T) {
        self.pq = pq
    }
}

/// 為協議實現默認方法
extension PQColorable where WarpperType == UIColor{
    /// 獲取紅色
    func red() -> CGFloat {
        var value: CGFloat = 0
        pq.getRed(&value, green: nil, blue: nil, alpha: nil)
        return value
    }
    /// 獲取綠色
    func green() -> CGFloat {
        var value: CGFloat = 0
        pq.getRed(nil, green: &value, blue: nil, alpha: nil)
        return value
    }
    /// 獲取藍色
    func blue() -> CGFloat {
        var value: CGFloat = 0
        pq.getRed(nil, green: nil, blue: &value, alpha: nil)
        return value
    }
}


extension UIColor{
    var pq: ExtensionPQColorable<UIColor>{
        return ExtensionPQColorable(pq: self)
    }
}



最后我們就可以在ViewController中調用啦

class ViewController: UIViewController {
    
    let data = Data(bytes: [0x2,0x33,0x54,0x78,0x1,0x2d,0x3a,0x5b,0x1,0x2d,0x3a,0x5b,0x1,0x2d,0x3a,0x5b])
    let color = #colorLiteral(red: 0.7450980544, green: 0.1568627506, blue: 0.07450980693, alpha: 1)

    @IBAction func toHexBtnClick(_ sender: Any) {
        print(data.pq.toHex())
    }
    @IBAction func toUInt8BtnClick(_ sender: Any) {
        print(data.pq.toUInt8())
    }
    @IBAction func redBtnClick(_ sender: Any) {
        print(color.pq.red())
    }
    @IBAction func greenBtnClick(_ sender: Any) {
        print(color.pq.green())
    }
    @IBAction func blueBtnClick(_ sender: Any) {
        print(color.pq.blue())
    }
}

打印結果如下:

02335478 012d3a5b 012d3a5b 012d3a5b 
[2, 51, 84, 120, 1, 45, 58, 91, 1, 45, 58, 91, 1, 45, 58, 91]
0.745098054409027
0.156862750649452
0.0745098069310188

OK,到這里應該就會如何去裝逼了,使命已經達成。撤!


別走,留下DEMO

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
【社區(qū)內容提示】社區(qū)部分內容疑似由AI輔助生成,瀏覽時請結合常識與多方信息審慎甄別。
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發(fā)布,文章內容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關閱讀更多精彩內容

  • 發(fā)現 關注 消息 iOS 第三方庫、插件、知名博客總結 作者大灰狼的小綿羊哥哥關注 2017.06.26 09:4...
    肇東周閱讀 15,028評論 4 61
  • 136.泛型 泛型代碼讓你可以寫出靈活,可重用的函數和類型,它們可以使用任何類型,受你定義的需求的約束。你可以寫出...
    無灃閱讀 1,652評論 0 4
  • 今天和同事,突然聊到了用手機刷公交車的問題,先暫且記錄一下這個想法,改天過來繼續(xù)補充細節(jié)
    Vicky_HMLiu閱讀 269評論 0 0
  • 記開遠市法律援助中心對周邊清塘子村21家村民援助實情 2017年3月初,冬的晨露未散,所里有些稀稀冷,急碎的腳步聲...
    一然夢飛閱讀 335評論 0 1
  • 死亡陰影籠罩的望族 維特根斯坦家族是真正的名門望族,歷史悠久資產雄厚。祖父是一位富有的猶太羊毛商。娶了維也納銀行家...
    麥麥sky閱讀 2,156評論 1 3

友情鏈接更多精彩內容