Swift 优雅的协议扩展
仿view.snp.xxx的调用形式
先看调用效果:“123456”.yy_Str.MD5ForLower32Bate()
"123456".yy_Str.MD5ForLower32Bate()
//类似:view.snp.xxx
为什么要这么做呢?好处在哪呢?
- 降低耦合度:传统的写法,直接在类别中添加一个方法或属性例如:
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)
}
}
- 降低不必要的冲突:当另一个工程师也有类似的需求时,他也新建文件写啦同样的方法,这就会有冲突,然后排查…
- 只需要一个属性,就能实现想要的扩展功能,代码简洁
如何实现
定义协议:YProtocolExtension.swift
//协议扩展
protocol YExtensionProtocol {
associatedtype YExtensionType //给谁写扩展例如:UIView、String、UIButton
var value: YExtensionType { get }
}
- 定义一个实现该协议的结构体
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
}
}
- 扩展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)
}
}
- 给String新增扩展:添加属性
//MARKL:有关字符串的扩展
extension String {
///第一种:直接指定类型的
var yy_Str: YExtensionStringEncodable {
return YExtensionStringEncodable.init(kit: self)
}
///第二种:泛型传递
var yy_kit: YExtensionKitStructTypeEncodable<String> {
return YExtensionKitStructTypeEncodable.init(kit: self)
}
}
- 在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