SwiftUI 結構體自動生成可編輯界面

2個關鍵點:一個是讀取、一個是寫入。
顯示界面:讀取結構體的字段名,字段類型,即可判斷、顯示相應的UI控件;
用戶寫入數據:需要知道每個UI控件和哪個字段進行綁定,另外,對字段需要有寫的權限。

嘗試Mirror【失敗】

第一個嘗試的方案是運用反射技術,在Swift中,使用的是Mirror。Mirror可以讀取結構體的屬性,但不能修改結構體。

嘗試Dictionary【失敗】

第二個嘗試的方案是使用字典Dictionary。即可讀取,也能寫入。
具體步驟是:

  1. 初始化結構體
  2. 通過JSONSerialization序列化成字典
  3. 遍歷字典顯示界面。。。[卡住]

單單是在讀取這裏,就遇到一個棘手的問題。Swift是強類型的語言,所以讀取Dictionary的嵌套字段,需要一長串的類型轉換。這就很難寫出簡潔易懂的代碼。
比如:

    var dic:[String: Any] = ["a": [1,2]]
    var value = (dic["a"] as! [Int])[0] 

難點是,我們如何去解析包含自定義類型的數組呢?
要知道 [Location] 、[User]和 [String] 可是不同類型.
原始類型畢竟數量有限,每個類型判斷一次沒問題。
但對於自定義的類型。以我目前的能力,不知道如何寫出兼容不同字典的解析代碼?很是頭大。

if let dic["a"] as [Location] {
    //...
} else if dic["a"] as [User] {
    ....
}
// ...無窮無盡的自定義類型

新的思考

能否像弱類型語言那樣(如JavaScript),我可以這樣去訪問一個字段 dic["a"][0]
而不用在乎 dic["a"]是不是數組,也不關心它是個什麼類型的數組,假如它是個數組,那就返回相應索引的值;假如不是個數組,就返回nil。
這樣的話,有2個好處:

  1. 對於讀取,因爲我們可以不必在乎是數組類型,管你是[Location]還是[User],我知道你是個數組就行。這樣可以寫出通用的遍歷代碼。
  2. 對於寫入,我們可以很容易的通過拼接的方式來修改嵌套字段。

站在巨人的肩膀

在網上查閱資料,發現SwiftyJSON框架。
官方使用示例:

let json = JSON(data: dataFromNetworking)
if let userName = json[0]["user"]["name"].string {
  //Now you got your value
}

看起來符合我的預期。

它的原理是把字典封裝到它自定義的JSON結構體裏,
通過JSON.object屬性進行get、set操作。
這個object實際上通過類型判斷,返回、修改不同的成員變量。

以下是SwiftyJSON的部分源碼:

    fileprivate var rawArray: [Any] = []
    fileprivate var rawDictionary: [String: Any] = [:]
    fileprivate var rawString: String = ""
    fileprivate var rawNumber: NSNumber = 0
    fileprivate var rawNull: NSNull = NSNull()
    fileprivate var rawBool: Bool = false
       /// Object in JSON
    public var object: Any {
        get {
            switch type {
            case .array:      return rawArray
            case .dictionary: return rawDictionary
            case .string:     return rawString
            case .number:     return rawNumber
            case .bool:       return rawBool
            default:          return rawNull
            }
        }
        set {
            //...    
        }
    }

最終可行方案

初始化結構體,並轉爲JSON,
使用KeyPath,作爲字段的唯一索引。格式如:"user.name"、"user.groups.0"。

並且,我爲KeyPath方案寫了個工具函數,1.可獲取JSON所有字段的KeyPath,2. 可通過JSON[KeyPath]的方式修改字段值。

這樣,就完全攻克讀、寫的技術難點了

  1. 遍歷JSON中的字段值,判斷類型顯示相應UI;【其實就是遍歷KeyPath】
  2. 能通過UI控件修改原JSON相應字段;[其實就是把JSON和KeyPath傳給UI]

源碼

https://gitee.com/tamiapp/swift-ui-struct-to-view

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章