Bo2SS

Bo2SS

2 應用開發篇(下)

《帶你領略 iOS 知識體系的全貌》,今天繼續應用開發篇(下)。

在這一篇,我們會講到 iOS 開發中的 JSON 解析、佈局框架、富文本、TDD/BDD 和編碼規範

image

26 | JSON 解析#

背景:不同編程語言之間進行數據通信,通信數據規範該如何確定?所以需要一種通用,而且各個編程語言都支持的數據格式。


接下來就輪到 JSON 出場了。

Source: codebrainer

JSON 的全稱是 JavaScript Object Notation,可見最初是被設計為 JavaScript 語言的一個子集,但最終因為和編程語言無關,所以 JSON 就成為了一種開放標準的常見數據格式。

目前很多編程語言都支持了 JSON 的生成和解析,所以 JSON 這樣的數據格式就滿足了背景裡提到的需求。


JSON 基於兩種結構

  • 鍵值對集合:具體實現有字典、Hash 表、對象、結構體等,示例:{"key1": "val1","key2": "val2"}

  • 有序值列表:具體實現有數組、向量、列表等,示例:[1,3,5]


JSON 的其它特點

  • 支持嵌套:上述值可以是字符串、數字、對象、數組、布爾值、空值中的任一種;

  • 不支持註釋;

  • 水平制表符、換行符、回車符都會被當做空格。


大多數語言的邏輯可以轉換成語法樹結構,而語法樹能夠用 JSON 來描述。所以 JSON 的使用場景有很多:

  1. 描述業務數據,使得業務數據能夠動態更新;

  2. 描述業務邏輯,以實現業務邏輯的動態化;

  3. 描述頁面佈局。


如何解析

蘋果原生提供了 NSJSONSerialization (OC) / JSONSerialization (Swift) 類來解析 JSON,相關的第三方框架有 JSONModel、Mantle、MJExtension、YYModel,它們都是基於原生類的封裝。

如果追求更高的解析性能,可以了解一下 simdjson(2019 年 2 月發布),號稱每秒可解析千兆字節 JSON 文件。相比按字節自頂向下遞歸解析的傳統 JSON 解析方式,其優化思路在於解析並行化,參考:

27 | 跟自動佈局比,Flexbox 好在哪?#

Flexbox 的 “地位”:是知名佈局庫 React Native、Weex 和 Texture(AsyncDisplayKit)採用的佈局思路,同時也是蘋果官方類 UIStackView 採用的佈局思路。

React Native 和 Weex 對 Flexbox 算法的實現,是一個叫作 Yoga 的 C++ 庫。


如下圖,Flexbox 算法的主要思想是,讓 flex container(容器)能夠改變其 flex item(項目的)寬高和順序,如通過擴大 / 縮小項目來適配(填充 / 防止超出)可用空間。

Source: W3C

關於 Flexbox 更詳細的講解,可以參考:


那跟自動佈局相比,Flexbox 好在哪呢

  1. 提供的佈局方法更方便、更全面、更規範;

  2. 響應式,跨平台性好:目前所有瀏覽器都已支持,同時在 iOS 和 Android 中也支持。

所謂響應式,是指不直接操作目標,而是通過代理達到操作的目的。

28 | 怎麼應對各種富文本表現需求?#

富文本是什麼?它是一段有屬性的字符串。

image

  • 可以包含不同字體、不同字號、不同背景、不同顏色、不同字間距的文字;

  • 還可以設置段落、圖文混排等等屬性。


然後,如何展示富文本呢?這裡分 2 種情況:

1)用 HTML 來描述的富文本

這種方式描述的富文本,可以直接使用 WKWebView 控件的 loadHTMLString:baseURL: 方法來展示。

此外,對於 HTML 裡的圖片資源,因為需要通過網絡請求來獲取,所以可以考慮緩存策略減少請求次數。

2)使用原生 iOS 代碼描述的富文本

長列表場景 (一次性返回多條數據交由前端渲染)一般對性能的要求更高,所以會使用這種方式描述的富文本。

這種方式描述的富文本,可使用蘋果官方的 TextKit 或者第三方的 YYText 來展示。

其中,YYText 有很多亮點

  1. 在異步文字佈局和渲染上的性能非常好;

  2. 兼容 UILabel 和 UITextView;

  3. 自定義的 NSMutableAttributedString 分類,不光簡化了基類,還增加了嵌入 UIView、CALayer 等功能。


小結

  • HTML 描述富文本更易讀、更容易維護;

  • 原生代碼描述富文本的性能更高。

所以如果想結合兩者的優勢,可以使用 HTML 描述富文本,然後在展示前先將 HTML 轉成原生代碼(可參考作者的 HTN 項目,實現了 HTML 代碼轉原生代碼的能力)。

富文本 → HTML → 原生代碼 → 展示

29 | 如何進行 TDD 和 BDD?#

背景:編寫影響範圍比較大的代碼時,需要檢驗的地方就非常多,相應地,人工檢查的時間成本也會非常高。

那麼,如何提高編寫代碼後的檢驗效率呢?

答案是開發、測試同步進行,盡早發現問題。


測試範圍上來劃分的話,測試可以分為:

  • 單元測試(開發者負責)

  • 集成測試(測試團隊負責)

  • 系統測試(測試團隊負責)

其中,單元測試也叫模塊測試,這個單元可能是一個類的方法,也可能是一個模塊的某個函數;同時,開發者要注意保證每個單元的職責清晰。


開發模式劃分的話,開發方式可以分為:

  • TDD(Test-driven development,測試驅動開發)

  • BDD(Behavior-driven development,行為驅動開發)

Source: testlodge


TDD 的開發思路是:

  1. 先編寫測試用例;

  2. 在不考慮代碼優化的情況下快速編寫功能實現代碼;

  3. 等功能開發完成後,在測試用例的保障下,進行代碼重構,以提高代碼質量。

它的測試用例主要針對開發中的最小單元,適合單元測試。

在思想上,TDD 和拿到功能需求後直接開發功能的區別是:

  • 先考慮如何對功能進行測試,再考慮如何編寫代碼,這給優化代碼提供了更多的時間和空間;

  • 即使幾個版本過後再來優化,只要能夠通過先前寫好的測試用例,就能夠保證代碼質量。

PS:有點 “不忘初心” 的那味道~


BDD 是 TDD 的進化,它:

  • 基於行為進行功能測試,使用 DSL(Domain Specific Language,領域特定語言)來描述測試用例;

  • 測試用例看起來和文檔一樣,更易讀、更好維護。

它的測試用例是對行為的描述,測試範圍更大一些,適合集成測試和系統測試。

同時,得益於 BDD 使用的 DSL 語言(規範、標準、可讀性高),不僅開發者可以使用 BDD 高效地發現問題,也方便測試團隊參與編寫。


BDD 的 OC 框架有 Kiwi、Specta、Expecta 等,Swift 框架有 Quick。

作者推薦 Kiwi 這個框架,因為它包含 Specta 的 DSL 模式,Expecta 框架的期望語法,以及 MocksStubs 能力,具體使用可以參考 Kiwi Wiki(Specs | Expectations | Mocks and Stubs | Asynchronous Testing)。

Mocks:模擬對象,如模擬 Null 對象、模擬類的實例、模擬協議的實例。

Stubs:存根,可以讓選擇器或消息模式返回固定的結果,支持真實對象和模擬對象。


小結

  • 無論是 TDD 還是 BDD,都是先寫測試用例(需要考慮到各種異常條件以及輸入輸出的邊界),再開發代碼;

  • 好的模塊化架構和 TDD 、BDD 是互相促進的。

作者建議:優先對基礎能力的功能開發使用 TDD 和 BDD,保證了基礎能力的穩定後,在時間允許的情況下,再考慮核心業務

30 | 如何制定一套合適的編碼規範?#

背景:一個團隊有了統一的編碼規範,才能更有效地避免團隊成員相互認同感缺失的問題(代碼風格不一致而導致的)。


那什麼是好的代碼規範,需要考慮哪些方面呢?

Source: quora

首先,可以參看一些優秀公司的代碼規範


接下來,是一份簡單的參考

  1. 常量:使用類型常量,而不是宏定義。

  2. 變量:明確體現出功能,最好加上類型做後綴;少用全局變量傳遞值,而是通過參數傳值(減少功能模塊間的耦合)。

  3. 屬性:OC 裡,儘量通過 get 方法來進行懶加載(避免無用的內存佔用和多餘的計算);Swift 裡,如果屬性是只讀的,可以省掉其 get 子句。

  4. 條件語句:減少或不使用默認處理,特別是使用 Switch 處理枚舉時(使用 Swift 編寫 Switch 語句時,如果不加 default 分支的話,當枚舉有新增值時,編譯器會提醒你增加分支處理);減少嵌套處理(增加可讀性),Swift 中可以充分利用 guard 語法。

  5. 循環語句:減少 continue 和 break 的使用(增加可讀性),Swift 中可以統一使用 guard 來代替。

  6. 函數:函數名體現目的;每個函數處理最小單位的邏輯,滿足單一職責原則;函數內儘量避免使用全局變量來傳遞數據(減少耦合,提高單元測試的準確性);注意檢查函數的入參(提高健壯性),Swift 裡的 guard 語法同樣適用於檢查入參。

  7. :在 OC 中,類的頭文件儘可能少地引入其他類的頭文件,而是通過 @class 來聲明,然後在實現文件裡再通過 #import 引入需要的頭文件(使用 @class 保證代碼編譯通過,使用 #improt 保證代碼運行通過,參考 OC 中 @class 和 #import 的區別——CSDN);對於繼承和遵循協議的情況,無法避免引入其他類裡的頭文件,所以在代碼設計時儘量減少繼承(繼承關係太多不利於代碼的維護和修改,比如修改父類時還需要考慮對所有子類的影響)。

  8. 分類: 分類裡增加的方法名儘量加上前綴,如果是系統自帶類的分類的話,就一定要加上前綴(避免產生方法名重複的問題);把一個類裡的公有方法分類到不同的分類裡,便於管理維護(特別適合多人維護各自不同功能代碼的場景)。

💡:

  • 代碼邏輯清晰是高質量代碼最基本、最必要的條件。如果代碼不清晰的話,那麼其他的擴展、重用、簡潔優雅都免談。

  • 寫代碼的首要任務是能讓其他人看得懂,避免過度工程化(針對特定業務的工程設計)。

  • 減少使用過新的語言特性和黑魔法,如果需要使用,則多補充註釋。


最後,如何將代碼規範落地執行呢?

最好的方式就是 Code Review(代碼審核)。通過 Code Review ,你可以:

  • 檢查代碼規範是否被團隊成員執行;

  • 同時及時指導代碼編寫不規範的同學。

Code Review 可以分為兩步走

  1. 先使用靜態檢查工具SwiftLintOCLint),對提交的代碼進行一次全面檢查。

  2. 然後,再進行人工檢查(審核人可以點贊、評論),除了能達到將代碼規範落地的效果外,還可以促進成員之間的溝通交流和相互學習。


好啦,應用開發篇馬上就要告一段落(還差一篇介紹 iOS 開發學習資料的加餐),下次就要開始原理篇的內容了,涉及 iOS 系統內核 XNU、iOS 黑魔法背後的原理……(🤫留點想象空間)。

Bo2SS 會竭盡全力把它們講明白,還請大家多多支持~咱們下次見!

載入中......
此文章數據所有權由區塊鏈加密技術和智能合約保障僅歸創作者所有。