使用 Swift 5 字符串插值快速構建 AttributeString

一直以來,在 Cocoa 體系裏構建富文本是一件很繁瑣的事情,使用 Foundation 框架裏的 NSAttributeString 來進行構建,有着要區分可變與不可變,傳入須要查閱文檔的參數字典,沒有類型檢查等種種彆扭之處。Swift 5 出現的新字符串插值特性,讓處理自定義字符串字面量成爲可能。git

Swift 5 的字符串插值

簡單來講,這個特性能讓開發者本身實現對字面量中插值的解析和邏輯實現。例如:github

let string:CustomString = "\(num: 10)"
複製代碼

這樣的字符串字面量,開發者能夠經過實現相似 func appendInterpolation(num: Int) 這樣的方法,實現對 num 的處理。要實現這樣的效果,大概分爲如下幾個步驟:express

  1. 自定義類型並遵循 ExpressibleByStringInterpolation
  2. 在類型中嵌套遵循 StringInterpolationProtocol 的插值類型
  3. 插值類型自定義一到多個不一樣參數的 func appenInterpolation(...) 重載方法,並處理對應參數的邏輯

這樣經過字符串插值,理論上能夠實現任意的功能,好比經過字符串構建成 SQL 操做,正則操做,生成 HTML 網頁,甚至感受能夠實現一些運行時的黑科技。swift

實現 AttributeString 處理

首先自定義類型,並先實現 ExpressibleByStringLiteral 用於支持字符串字面量(ExpressibleByStringLiteralExpressibleByStringLiteral 的子協議)。這樣咱們就能夠經過字符串字面量構建一個沒有任何屬性的 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))
    }
}
複製代碼

EasyText 使用

筆者將 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 均有類型檢查
  • 支持多平臺,iOS/macOS
  • 支持大部分經常使用 NSAttributedString.Key,暫時沒有支持的提供接口構建
  • 支持經常使用的運算符,如 ++=,以及與其餘類型 StringNSAttributedString 的運算
  • 支持插入圖片

更多使用方法詳見 例子code

最後

EasyText 已開源,能夠經過 Cocoapods、Cathrage、SwiftPackageManager 進行集成。

若是您以爲有幫助,不妨給個 star 鼓勵一下,有任何問題歡迎評論。

參考連接

StringInterpolation in Swift 5 — Introduction

StringInterpolation in Swift 5 — AttributedStrings

Fix ExpressibleByStringInterpolation

相關文章
相關標籤/搜索