Swift elegant protocol extension (MD5 encryption as an example)

Keywords: Swift Attribute

Swift elegant protocol extension

Call form of imitating view.snp.xxx

First look at the call effect: "123456". yy_Str.MD5ForLower32Bate()

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

Why do you do this? What are the benefits?

  1. Reduce coupling: in traditional writing, add a method or attribute directly to the category, for example:
extension String {
    ///Authentication ID No.
    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. Reduce unnecessary conflicts: when another engineer has similar requirements, he also creates a new file and writes the same method, which will lead to conflicts, and then troubleshoot...
  2. Only one attribute is needed to realize the desired extension function, and the code is simple.

How to achieve

Definition protocol: yprotocollextension.swift

//Protocol extension
protocol YExtensionProtocol {
    associatedtype YExtensionType //Write extension to: UIView, String, UIButton
    var value: YExtensionType { get }
}
  1. Define a structure to implement the protocol
struct YExtensionKitStructTypeEncodable<T>: YExtensionProtocol {
///Implementation protocol properties
    var value: T
    typealias YExtensionType = T //Specify type (pass in generics)
    ///Construction method
    init(kit: T) {
        self.value = kit
    }
}
  1. We can also specify the type directly
struct YExtensionStringEncodable: YExtensionProtocol {
///Implementation protocol properties
    var value: String
    typealias YExtensionType = String //Specified type
    ///Construction method
    init(kit: String) {
        self.value = kit
    }
}
  1. Extend YExtensionProtocol to realize MD5 encryption in related strings

Note: if the function defined in the protocol is implemented in the protocol itself, it is an optional type. Otherwise, the inheritance protocol must be implemented.

Take String for example: MD5 encryption

import CommonCrypto

//MARK:String-MD5 encryption 32-bit
//where YExtensionType == String specifies YExtensionType: the type
extension YExtensionProtocol where YExtensionType == String {
    ///MD5 encryption 32-bit lowercase
    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 encryption 32-bit uppercase
    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. Add extension to String: add attribute
//MARKL: String extension
extension String {
///First: directly specify the type of
    var yy_Str: YExtensionStringEncodable {
        return YExtensionStringEncodable.init(kit: self)
    }
    ///Second: generic passing
    var yy_kit: YExtensionKitStructTypeEncodable<String> {
        return YExtensionKitStructTypeEncodable.init(kit: self)
    }
}
  1. The test results in ViewController are as follows
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())
    }
// The output results are as follows:
e10adc3949ba59abbe56e057f20f883e
E10ADC3949BA59ABBE56E057F20F883E
-----------------
e10adc3949ba59abbe56e057f20f883e
E10ADC3949BA59ABBE56E057F20F883E

The complete core code is as follows:

//
//  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 extension
protocol YExtensionProtocol {
    associatedtype YExtensionType
    var value: YExtensionType { get }
}
///Extension basis of Struct type
struct YExtensionKitStructTypeEncodable<T>: YExtensionProtocol {
    var value: T
    typealias YExtensionType = T
    ///Construction method
    init(kit: T) {
        self.value = kit
    }
}
struct YExtensionStringEncodable: YExtensionProtocol {
    ///Implementation protocol properties
    var value: String
    typealias YExtensionType = String //Specify type (pass in generics)
    ///Construction method
    init(kit: String) {
        self.value = kit
    }
}
/////Extension basis of Class type
//final class YExtensionKitClassTypeEncodable<T>: YExtensionProtocol {
//    / / generic
//    var value: T
//    typealias YExtensionType = T
//    ///Construction method
//    init(kit: T) {
//        self.value = kit
//    }
//}
//MARK:String-MD5 encryption 32-bit
extension YExtensionProtocol where YExtensionType == String {
    ///MD5 encryption 32-bit lowercase
    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 encryption 32-bit uppercase
    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 about string
extension String {
    var yy_Str: YExtensionStringEncodable {
        return YExtensionStringEncodable.init(kit: self)
    }
    var yy_kit: YExtensionKitStructTypeEncodable<String> {
        return YExtensionKitStructTypeEncodable.init(kit: self)
    }
}

Posted by Shaped on Tue, 22 Oct 2019 14:09:25 -0700