在OC里面中耻姥,Category大家一定不陌生,他可以很好的為我們服務(wù)有咨,給指定的類實(shí)現(xiàn)系統(tǒng)不提供的方法琐簇。
- 例子可能不恰當(dāng),無關(guān)緊要座享,重點(diǎn)不是OC
比如要實(shí)現(xiàn):把Data轉(zhuǎn)化為一個UInt8的數(shù)組
我們可能會這樣子寫
UInt8 *bytes = (UInt8 *)data.bytes;
現(xiàn)在我們不想像上面那個樣子婉商,強(qiáng)制類型轉(zhuǎn)換,直接就是UInt8的數(shù)組渣叛,我們就可以創(chuàng)建一個Category丈秩,然后實(shí)現(xiàn)方法
.h
- (UInt8 *)toUInt8;
.m
- (UInt8 *)toUInt8{
return (UInt8 *)data.bytes;
}
實(shí)現(xiàn)了上面的方法之后,到需要的地方引入頭文件就可以實(shí)現(xiàn)這樣子調(diào)用
UInt8 *bytes = data.toUInt8;
這樣子淳衙,我們就可以在實(shí)現(xiàn)了對NSData這個類的擴(kuò)展蘑秽,并且是無污染的,拖到任何一個工程就可以使用(當(dāng)然箫攀,例子中的命名方式不是很靠譜肠牲,這里忽略,重點(diǎn)不是他)靴跛。
現(xiàn)在來到Swift中缀雳,如果我們也要實(shí)現(xiàn)如上的功能,我們可以使用Extension梢睛,也可以很方便的完成它肥印。
新建一個Swift文件,然后實(shí)現(xiàn)如下代碼:
extension Data {
func toUInt8() -> [UInt8]{
var bytes: [UInt8] = [UInt8](repeating: 0, count: count)
copyBytes(to: &bytes, count: count)
return bytes
}
}
調(diào)用如下:
let data = Data(bytes: [0,1,2,3,4,5,6,7,8])
print(data.toUInt8())
打印結(jié)果:
[0, 1, 2, 3, 4, 5, 6, 7, 8]
假設(shè)你現(xiàn)在這個代碼就寫完啦绝葡,也沒有問題,可以達(dá)到預(yù)想的效果了竖独,然后新來的了一個工程師,然后他也需要把Data轉(zhuǎn)化為[UInt8]挤牛,但是代碼是你寫的莹痢,他并不知道啊。
- 第一種情況 于是乎他又寫了一個方法
UInt8
墓赴,實(shí)現(xiàn)的功能和你的一樣竞膳,這樣子就會有兩個功能一樣,只是命名方式不一樣的方法了诫硕。 - 第二種情況 他也寫了一個和你命名方式一樣的方法,但是他也新建了一個文件坦辟,然后你們兩個方法就沖突了,他就很納悶章办,黑人問號锉走?滨彻??,然后就是一頓查找……
然后就是隨著你的需求增加挪蹭,你添加的方法越來越多亭饵,當(dāng)你去了另外一家公司,你的這些成果本來是想著拖進(jìn)去就用梁厉,但是卻有了耦合辜羊,這豈不是很尷尬?
所以在Swift有了一種更優(yōu)雅的擴(kuò)展方法:協(xié)議擴(kuò)展
接下來用一個Demo去實(shí)現(xiàn)它词顾,看看他到底有多爽0送骸!H忭铩昔驱!
正題開始啦!I先獭舍悯!
1、 布局UI睡雇,并且他事件拖入到ViewController
中
2萌衬、新建一個Swift文件 PQDataEncodable.swift
這里需要注意的是:
Swift標(biāo)準(zhǔn)庫為我們提供了55中協(xié)議,他們的命名方式有著自己規(guī)則它抱,基本是以“Type”秕豫、“able'”、“Convertible”結(jié)尾观蓄,分別代表了“可以被當(dāng)做XX類型”混移、“具備某種能力或特性”、“能夠進(jìn)行改變或者變換”侮穿。所以在命名的時候應(yīng)該盡可能遵守這一套規(guī)則歌径,便于開發(fā)人員之間的高校合作。
3亲茅、創(chuàng)建一個協(xié)議回铛,實(shí)現(xiàn)它。
- 3.1 創(chuàng)建一個協(xié)議先:
protocol PQDataEncodable {
/// 關(guān)聯(lián)類型
associatedtype WarpperType
/// 這個就是命名克锣,我這里使用pq茵肃,你可以使用你的,比如:SnapKit袭祟,他的就是 view.snp.XXXX
var pq: WarpperType { get }
}
- 3.2 創(chuàng)建一個結(jié)構(gòu)體验残,繼承協(xié)議
struct ExtensionPQDataEncodable<T>: PQDataEncodable {
/// T 泛型
let pq: T
/// 構(gòu)造方法
init(pq: T) {
self.pq = pq
}
}
- 3.3 很重要的一環(huán)來了,為自己的協(xié)議添加默認(rèn)實(shí)現(xiàn)方法
/// 這里指定 WrapperType 是 Data巾乳,所以在 PQDataEncodable 中的 pq 就是 Data 類型了
extension PQDataEncodable where WarpperType == Data {
/// 方法名 返回參數(shù)
func toUInt8() -> [UInt8]{
/// 根據(jù)數(shù)組長度您没,創(chuàng)建數(shù)組
var bytes = [UInt8](repeating: 0, count: pq.count)
/// 把 Data 的 Bytes 拷貝到 數(shù)組中
pq.copyBytes(to: &bytes, count: pq.count)
/// 返回數(shù)組
return bytes
}
func toHex() -> String {
/// 創(chuàng)建一個字符串
var hex: String = ""
/// 遍歷數(shù)組鸟召,在轉(zhuǎn)換為16進(jìn)制添加到字符串中
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中添加一個結(jié)構(gòu)體欧募,由于這個結(jié)構(gòu)體是繼承我自己的協(xié)議的,所以就擁有了我協(xié)議里面默認(rèn)的實(shí)現(xiàn)方法喻犁。
extension Data {
var pq: ExtensionPQDataEncodable<Data> {
return ExtensionPQDataEncodable(pq: self)
}
}
然后我們就可以在ViewController
中這樣子調(diào)用了
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) {
}
}
輸出結(jié)果如下:
02335478 012d3a5b 012d3a5b 012d3a5b
[2, 51, 84, 120, 1, 45, 58, 91, 1, 45, 58, 91, 1, 45, 58, 91]
這樣子整個逼格就提高啦槽片,但是你可能會有疑問何缓,為什么要新建一個結(jié)構(gòu)體呢肢础??碌廓?
我們在UIView的時候不是可以直接指定么传轰?
例如下面的寫法:
import UIKit
protocol TEST where Self : UIView {
}
然后我們就嘗試的這樣子寫:
protocol TEST where Self : Data {
}
我們進(jìn)入UIView,看看他的定義
NS_CLASS_AVAILABLE_IOS(2_0) @interface UIView : UIResponder <NSCoding, UIAppearance, UIAppearanceContainer, UIDynamicItem, UITraitEnvironment, UICoordinateSpace, UIFocusItem, CALayerDelegate>
在進(jìn)入Data谷婆,看看他的定會
public struct Data : ReferenceConvertible, Equatable, Hashable, RandomAccessCollection, MutableCollection, RangeReplaceableCollection
一個是Class
慨蛙、一個是Struct
,所以我們需要一個Struct
來繼承協(xié)議纪挎,不可以直接對原有的struct進(jìn)行處理期贫。
剛才分析到Class
就可以這樣子搞,那么也就是說這個Struct
也可以是一個Class
异袄,然后我們就來實(shí)驗(yàn)一下通砍。
4、新建一個協(xié)議 PQColorable.swift
然后實(shí)現(xiàn)如下代碼
/// 新建一個協(xié)議
protocol PQColorable {
/// 關(guān)聯(lián)類型
associatedtype WarpperType
var pq: WarpperType { get }
}
/// 定義一個類
final class ExtensionPQColorable<T>: PQColorable {
/// 泛型
let pq: T
/// 構(gòu)造方法
init(pq: T) {
self.pq = pq
}
}
/// 為協(xié)議實(shí)現(xiàn)默認(rèn)方法
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
}
/// 獲取藍(lán)色
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中調(diào)用啦
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())
}
}
打印結(jié)果如下:
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