面向plist的小白配置化iOS編程

很多時候在app團隊作業時候會有這樣的場景:

  • server 端小伙伴總是很忙,總是不愿意配合我們該接口
  • 我們客戶端總需要重復搭建各類表單/表單型展示頁,每次都要在代碼里改datasource,改model等麻煩的事,哪怕框架共通寫的再好也要面對重復的代碼發呆
普通工作流

如果server的api返回的就是這樣的數據,那說明你遭遇的是正常待遇,那如果你說,唉?不對啊,我們有特地為app服務的專屬server團隊,那...你可以直接拉到下面看~

每當遇到這樣的場景,遭受正常待遇的我們總會想到設計下面這樣個model:
<pre>struct Person
{
var id : String!
var name : String!
var salary : Double = 0
var summary : String!
var description : String!

var displayedDiscription : String  {
    return "PersonId : \(id) \n Description : \(description)"
}

var displayedSalary : String  {
    return currencyGenerator(currencyDoubleValue: salary)
}

func currencyGenerator(currencyDoubleValue : Double) -> String
{
    return ""
}

init(json : [String : Any]) {

}
}</pre>

然后為了完成上面右邊的View的需求,我們會見個tableview,然后為這個親愛的tableview做個特殊的datasource,比如這樣:
<pre>func setupData() -> [String : Any]
{
let sampleSource = ["id" : "10000", "name" : "Fish", "salary" : 5000 , "summary" : "fff", "description" : "sss"] as [String : Any]
let person = Person(json : sampleSource)
return ["Name" : person.name,
"Salary" : person.displayedSalary ,
"Summary" : person.summary ,
"Desciprtion" : person.displayedDiscription]

}</pre>
后續的就不看了,大家也都猜得出。

我們辛辛苦苦做完了,上線了結果隔壁產品同學說,
呀,我們想加個字段,加一行手機號之類的東西,
呀,我們還想拿掉那個summary,感覺沒什么用,
哎呀呀,我們還要調整個順序,把Salary放到最下面...

呀呀呀,呀你妹啊 T_T 你以為這改動很簡單么,要加字段,要加xxx,要發版本上appstore...

那回過頭想想每次這樣做,我們的心會不會很累?可能server 端的同學會覺得這就是我們要做的事,可是重復寫這些code,每次要改那么多分散的地方,我們會不會很累?我們不覺得累,我們的xcode都會累呢。

所以我們靜下心來看下上面那個View,其實我們可以在每行都找到共通特征:
比如左邊有個title,右邊有個value,
那我們是不是可以有個Row的對象,里面有2個屬性:key和value,
key就是左邊顯示的文案,value是動態變化的
所以有了這樣的對象:
<pre>struct ConfigRow
{
// left title
var key : String!

// right title
var value : String!

}</pre>

那是不是如果我們有了5個這樣的對象,就能滿足上面那個View里的結果了呢,當然你可以選擇創建5個ConfigRow,然后湊成個數組作為datasource。但是這個做法,依舊很笨,依舊要改代碼;

這時候,傳說中的plist就要登場了,

我們是不是可以把這5個對象放在plist中,然后做一系列反序列化的方法把plist構建成我們要的數組datasource是不是就好了呢?因為這一系列方法肯定是共通的,所以每次做新類似內容,我們只需要建立個新的plist,然后調用共通方法構建datasource,然后調用應該已經可能被共通抽離出來的tableview構建方法,這樣就能完成這樣個簡單模塊的編寫了。
最重要的是,每次有文案修改,你只需要修改plist中內容就行了,這樣哪怕是別的不是負責你這個模塊的開發者來協助,他也能很快完成,畢竟字他總認識~

但是,我們需要對上面的Row進行下擴展,我們還需要加上顏色和排序的屬性,來隨意控制相應的屬性:
<pre>struct ConfigRow
{
// left title
var key : String!

// right title
var value : String!
var sortOrder : Int = 0
var color : String = ""

}</pre>

當然你還可以新增別的,比如左邊title的樣式屬性,右邊的value的樣式屬性等等等。


plist配置

這樣,一個白板就構建完了,我們的tableView上已經華麗的自動出現了那些固定文案,比如左側的所有label,或者順序/顏色;但是,最重要的右邊文案從哪來填充呢?

這里提供個最簡單的path方式,我們在plist中每個row的displayValue的默認值寫成對應的json中的key值,比如name的displayValue就填value,然后在cell的設置row的方法中:
<pre>leftTitle.text = model.value(forKey : row.displayValue)</pre>

這樣的思路就能解決白板填充的問題了,如果需要存下值的化,我們最終的ConfigRow可以變成這樣:
<pre>struct ConfigRow
{
// left title
var key : String!

// right title
var value : String!

// json中對應的key值
var valuePath : String!

var sortOrder : Int = 0
var color : String = ""

}</pre>

valuePath就是我們可以寫死的key值,而從json中獲取來的數據可以塞到value中,這樣保存著也方便以后用

再擴展下,比如這是個填寫型表單頁

填寫表單plist

也是一左一右的構造,只是右邊是個輸入框了,我們針對輸入框做了一系列屬性來控制,比如

  • 右邊框的樣式,可能是輸入,也可能是日歷,也可能是選擇,這些通過枚舉后在共通框架中實現就行了
  • 輸入限制的正則表達式regex
  • 輸入框鍵盤的樣式:數字/字母等

同時我們把單個Row的cell相應屬性也抽到了plist中修改:

  • cell的identifier重用標示,其實也就等于你可以指定當前Row用什么樣的cell來顯示
  • cell的segue,因為我們用的是storyBoard跳轉,所以可以通過segueIdentifier來直接在tableView的didSelect方法中進行跳轉,當然別的跳轉方式也可以支持喲,就看需求了
  • cell的高度height,如果不需要自動計算的或者手動計算的話,我們直接把cell的高度也放在了ConfigRow中進行修改,這樣controller中寫死的東西又少了

當然還有別的功能就不一一列舉了。

其實這一整套是很簡答的思路設計,重點核心就是我們去掉了業務對象化的思路,而是采用了針對View的單行進行對象化,即原本縱向的考慮變成了橫向,真正站在tableView的角度想他需要什么。
這樣的設計可以把我們從修改代碼的常規邏輯中抽離出來,其實每次我們只需要改相應的plist,也能完成看似很簡單其實真的很簡單的問題,何不嘗試一下呢?

當然,之前提到,如果你有一個很好的專門服務的server服務團隊,這套plist就可以放在服務端,這樣他們也可以通過配置文件來直接配置表單了;而server端哪怕沒有這個條件,我們也可以把這些配置放在我們工程中,這樣每次開發時候也方便我們修改了。

當然,這期中最有問題的應該就是上面的valuePath這一段了,如果遇到復雜的需求需要同一個位置顯示多個字段拼接的,比如:
Description = ID + Descprition
的顯示該怎么辦呢?
下期中會介紹專門為這個需求而誕生的工具 CodingForP,
https://github.com/SpiciedCrab/CodingForP
到時候我們就能明白這有多有趣了。

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容