Swift 優雅的協議擴展

仿view.snp.xxx的調用形式

先看調用效果:“123456”.yy_Str.MD5ForLower32Bate()

"123456".yy_Str.MD5ForLower32Bate()
//類似:view.snp.xxx

爲什麼要這麼做呢?好處在哪呢?

  1. 降低耦合度:傳統的寫法,直接在類別中添加一個方法或屬性例如:
extension String {
    ///驗證身份證號
    func validateidnum() -> Bool {
        let idRegex = "^(\\d{14}|\\d{17})(\\d|[xX])$"
        let idTest:NSPredicate = NSPredicate(format: "SELF MATCHES %@", idRegex)
        return idTest.evaluate(with: self)
    }
}
  1. 降低不必要的衝突:當另一個工程師也有類似的需求時,他也新建文件寫啦同樣的方法,這就會有衝突,然後排查…
  2. 只需要一個屬性,就能實現想要的擴展功能,代碼簡潔

如何實現

定義協議:YProtocolExtension.swift

//協議擴展
protocol YExtensionProtocol {
    associatedtype YExtensionType //給誰寫擴展例如:UIView、String、UIButton
    var value: YExtensionType { get }
}
  1. 定義一個實現該協議的結構體
struct YExtensionKitStructTypeEncodable<T>: YExtensionProtocol {
///實現協議的屬性
    var value: T
    typealias YExtensionType = T //指定類型(傳入泛型)
    /// 構造方法
    init(kit: T) {
        self.value = kit
    }
}
  1. 同樣我們也可以直接指定類型
struct YExtensionStringEncodable: YExtensionProtocol {
///實現協議的屬性
    var value: String
    typealias YExtensionType = String //指定類型
    /// 構造方法
    init(kit: String) {
        self.value = kit
    }
}
  1. 擴展YExtensionProtocol,實現相關String中MD5加密的功能

注意:凡是協議中定義的函數自己在協議中實現啦,他就是可選的類型,反之,是繼承協議着必須實現。

String爲例:MD5加密

import CommonCrypto

//MARK:String-MD5加密32位
//where YExtensionType == String 指定YExtensionType:爲那種類型
extension YExtensionProtocol where YExtensionType == String {
    ///MD5加密32位小寫
    func MD5ForLower32Bate() -> String {
        let str = value.cString(using: .utf8)
        let strLen = CUnsignedInt(value.lengthOfBytes(using: .utf8))
        let digestLen = Int(CC_MD5_DIGEST_LENGTH)
        let result = UnsafeMutablePointer<CUnsignedChar>.allocate(capacity: digestLen)
        CC_MD5(str!, strLen, result)
        let hash = NSMutableString.init()
        for i in 0..<digestLen {
            hash.appendFormat("%02x", result[i])
        }
        result.deinitialize(count: digestLen)
        return String(hash)
    }
    ///MD5加密32位大寫
    func MD5ForUpper32Bate() -> String {
        let str = value.cString(using: .utf8)
        let strLen = CUnsignedInt(value.lengthOfBytes(using: .utf8))
        let digestLen = Int(CC_MD5_DIGEST_LENGTH)
        
        let result = UnsafeMutablePointer<CUnsignedChar>.allocate(capacity: digestLen)
        CC_MD5(str!, strLen, result)
        let hash = NSMutableString()
        for i in 0..<digestLen {
            hash.appendFormat("%02X", result[i])
        }
        result.deinitialize(count: digestLen)
        return String(hash)
    }
}
  1. 給String新增擴展:添加屬性
//MARKL:有關字符串的擴展
extension String {
///第一種:直接指定類型的
    var yy_Str: YExtensionStringEncodable {
        return YExtensionStringEncodable.init(kit: self)
    }
    ///第二種:泛型傳遞
    var yy_kit: YExtensionKitStructTypeEncodable<String> {
        return YExtensionKitStructTypeEncodable.init(kit: self)
    }
}
  1. 在ViewController測試結果如下
override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view.
        print("123456".yy_kit.MD5ForLower32Bate())
        print("123456".yy_kit.MD5ForUpper32Bate())
        print("——————————————————————————————————")
        print("123456".yy_Str.MD5ForLower32Bate())
        print("123456".yy_Str.MD5ForUpper32Bate())
    }
// 輸出結果如下:
e10adc3949ba59abbe56e057f20f883e
E10ADC3949BA59ABBE56E057F20F883E
——————————————————————————————————
e10adc3949ba59abbe56e057f20f883e
E10ADC3949BA59ABBE56E057F20F883E

核心完整代碼如下

//
//  YExtensionProtocol.swift
//  YExtentionDemo
//
//  Created by bruce yao on 2019/7/18.
//  Copyright © 2019 bruce yao. All rights reserved.
//
import Foundation
import UIKit
import CommonCrypto

//協議擴展
protocol YExtensionProtocol {
    associatedtype YExtensionType
    var value: YExtensionType { get }
}
///Struct類型的擴展基礎
struct YExtensionKitStructTypeEncodable<T>: YExtensionProtocol {
    var value: T
    typealias YExtensionType = T
    /// 構造方法
    init(kit: T) {
        self.value = kit
    }
}
struct YExtensionStringEncodable: YExtensionProtocol {
    ///實現協議的屬性
    var value: String
    typealias YExtensionType = String //指定類型(傳入泛型)
    /// 構造方法
    init(kit: String) {
        self.value = kit
    }
}
/////Class類型的擴展基礎
//final class YExtensionKitClassTypeEncodable<T>: YExtensionProtocol {
//    /// 泛型
//    var value: T
//    typealias YExtensionType = T
//    /// 構造方法
//    init(kit: T) {
//        self.value = kit
//    }
//}
//MARK:String-MD5加密32位
extension YExtensionProtocol where YExtensionType == String {
    ///MD5加密32位小寫
    func MD5ForLower32Bate() -> String {
        let str = value.cString(using: .utf8)
        let strLen = CUnsignedInt(value.lengthOfBytes(using: .utf8))
        let digestLen = Int(CC_MD5_DIGEST_LENGTH)
        let result = UnsafeMutablePointer<CUnsignedChar>.allocate(capacity: digestLen)
        CC_MD5(str!, strLen, result)
        let hash = NSMutableString.init()
        for i in 0..<digestLen {
            hash.appendFormat("%02x", result[i])
        }
        result.deinitialize(count: digestLen)
        return String(hash)
    }
    ///MD5加密32位大寫
    func MD5ForUpper32Bate() -> String {
        let str = value.cString(using: .utf8)
        let strLen = CUnsignedInt(value.lengthOfBytes(using: .utf8))
        let digestLen = Int(CC_MD5_DIGEST_LENGTH)
        
        let result = UnsafeMutablePointer<CUnsignedChar>.allocate(capacity: digestLen)
        CC_MD5(str!, strLen, result)
        let hash = NSMutableString()
        for i in 0..<digestLen {
            hash.appendFormat("%02X", result[i])
        }
        result.deinitialize(count: digestLen)
        return String(hash)
    }
}

//MARK:有關字符串的擴展
extension String {
    var yy_Str: YExtensionStringEncodable {
        return YExtensionStringEncodable.init(kit: self)
    }
    var yy_kit: YExtensionKitStructTypeEncodable<String> {
        return YExtensionKitStructTypeEncodable.init(kit: self)
    }
}

Swift 5.0協議擴展 Cocoapods下載

鏈接:https://github.com/YaoChengZhen/YYExtentions.git

source 'https://github.com/CocoaPods/Specs.git'
platform :ios, '9.0'

target 'TargetName' do
pod 'YYExtentions', 
end
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章