一直以來,在 Cocoa 體系裏構建富文本是一件很繁瑣的事情,使用 Foundation 框架裏的 NSAttributeString
來進行構建,有着要區分可變與不可變,傳入須要查閱文檔的參數字典,沒有類型檢查等種種彆扭之處。Swift 5 出現的新字符串插值特性,讓處理自定義字符串字面量成爲可能。git
簡單來講,這個特性能讓開發者本身實現對字面量中插值的解析和邏輯實現。例如:github
let string:CustomString = "\(num: 10)"
複製代碼
這樣的字符串字面量,開發者能夠經過實現相似 func appendInterpolation(num: Int)
這樣的方法,實現對 num
的處理。要實現這樣的效果,大概分爲如下幾個步驟:express
ExpressibleByStringInterpolation
StringInterpolationProtocol
的插值類型func appenInterpolation(...)
重載方法,並處理對應參數的邏輯這樣經過字符串插值,理論上能夠實現任意的功能,好比經過字符串構建成 SQL 操做,正則操做,生成 HTML 網頁,甚至感受能夠實現一些運行時的黑科技。swift
首先自定義類型,並先實現 ExpressibleByStringLiteral
用於支持字符串字面量(ExpressibleByStringLiteral
是 ExpressibleByStringLiteral
的子協議)。這樣咱們就能夠經過字符串字面量構建一個沒有任何屬性的 NSAttributedString
。安全
public struct EasyText {
public let attributedString: NSAttributedString
}
extension EasyText: ExpressibleByStringLiteral {
public init(stringLiteral: String) {
attributedString = NSAttributedString(string: stringLiteral)
}
}
複製代碼
接着實現 ExpressibleByStringInterpolation
協議,嵌套插值類型,並遵循 StringInterpolationProtocol
。該插值構建完會經過 init(stringInterpolation: StringInterpolation)
方法來實現構建自定義類型。appendLiteral
方法用於正常的字符串類型的插值處理。app
extension EasyText: ExpressibleByStringInterpolation {
public init(stringInterpolation: StringInterpolation) {
attributedString = NSAttributedString(attributedString: stringInterpolation.rawAttributedString)
}
public struct StringInterpolation:StringInterpolationProtocol {
let rawAttributedString:NSMutableAttributedString
public init(literalCapacity: Int, interpolationCount: Int) {
rawAttributedString = NSMutableAttributedString()
}
public func appendLiteral(_ literal:String) {
rawAttributedString.append(NSAttributedString(string: literal))
}
}
}
複製代碼
接下來實現一到多個 appendInterpolation
方法,例如讓插值支持添加 NSTextAttachment
:框架
public struct StringInterpolation:StringInterpolationProtocol {
// ...
public func appendInterpolation(attachment:NSTextAttachment) {
rawAttributedString.append(NSAttributedString(attachment: attachment))
}
}
複製代碼
筆者將 NSAttributedString
裏的屬性都使用字符串插值進行了支持,實現了一個幾百行的庫。使用這個庫,能夠作到如下面簡單的方式構建 NSAttributedString
:性能
let text:EasyText = "\("font is 30 pt and color is yellow", .font(.systemFont(ofSize: 20)), .color(.blue))"
textView.attributedText = text.attributedString
複製代碼
有如下特性:spa
NSAttributedString.Key
均有類型檢查NSAttributedString.Key
,暫時沒有支持的提供接口構建+
、+=
,以及與其餘類型 String
、NSAttributedString
的運算更多使用方法詳見 例子。code
EasyText 已開源,能夠經過 Cocoapods、Cathrage、SwiftPackageManager 進行集成。
若是您以爲有幫助,不妨給個 star 鼓勵一下,有任何問題歡迎評論。
StringInterpolation in Swift 5 — Introduction