如何正確地寫好一個界面

来源:http://www.cnblogs.com/wsnb/archive/2016/01/11/5120065.html
-Advertisement-
Play Games

寫界面可以說是每位移動應用開發者的基本功,也是一位合格移動應用開發者繞不過去的坎。但就如不是每一位開發者都能夠成為合格的開發者一樣,本人在 不同的團隊中發現,甚少有人能夠編寫出合格的UI代碼;而非常奇怪的是,在很多的開發者論壇上看到我們移動開發者更多關註於某個控制項或者是動畫,但卻很少 看到深入剖析U...


寫界面可以說是每位移動應用開發者的基本功,也是一位合格移動應用開發者繞不過去的坎。但就如不是每一位開發者都能夠成為合格的開發者一樣,本人在 不同的團隊中發現,甚少有人能夠編寫出合格的UI代碼;而非常奇怪的是,在很多的開發者論壇上看到我們移動開發者更多關註於某個控制項或者是動畫,但卻很少 看到深入剖析UI機制,指導UI開發的文章。

由於界面涉及到的方面實在過於廣泛,本文不可能事無巨細,一一道來,所以本文先立足於點,深入剖析iOS UI系統中不被重視卻非常重要的機制,幫助本文讀者對iOS的UI系統有整體瞭解;進而以點帶面,拓展到UI邏輯設計和架構設計模式的討論;最後讀文而有 所思有所得,設計開發出高效、易用、流暢的UI模塊。

本文章節如下:

  1. 基礎與本質:說明普遍意義上的UI系統的三大模塊,讓讀者從整體上對UI系統有清楚的認識。
  2. View:深入View的內部機制,View與Layer之間的關係,以及Offscreen Render;
  3. ViewController:講解ViewController在UI系統中所扮演的角色,以及UI架構設計中ViewController運用和實踐;
  4. MVC、MVP、MVVM:簡單分析三種主流的架構設計模式及其異同,並簡單提出了一些做架構設計意見和想法;
  5. 總結。

各章節間沒有必然的聯繫,讀者可以選擇感興趣章節閱讀。



1. 基礎與本質

終端App開發區別於後端開發最大的不同,就是終端開發很大部分的邏輯是為用戶提供界面以供人機交互,即所謂的UI(User Interface)。所以所有的UI架構主要關註三大模塊:界面佈局管理,渲染及動畫、事件響應;

 

1.1 佈局管理

即在規定的坐標系統上,按照一定的層級順序位置大小排布在容器內。一個UI系統必然有個基於坐標的佈局管理系統,不管是Windows、Sysbian,還是Andorid、iOS。好的佈局管理機制直接影響界面邏輯實現的難易程度;

我們現在日常接觸到的App的UI坐標系統都是二維的,我們現在玩的3D游戲,受限於二維的展示屏幕,所以實質上只是三維在二維上的映射投影。我們 一直在往更高的維度發展:全息影像、Hololens等等。在此可以設想下,未來我們構建界面的佈局管理很可能就是基於真實三維坐標。

 

1.2 動畫及渲染

UI之所以叫User Interface,就是因為UI通過視覺上的展示,為用戶提供信息。這些信息的展示需要通過一系列複雜的計算,最後操作液晶體展示在顯示屏上,這一系列過程就是渲染和動畫;

下圖就是應用界面渲染到展示的流程:

Render

引自WWDC2014 #419 Advanced Graphics and Animations for iOS Apps

這裡不展開來講,推薦沒看過的同學都認真觀看,能夠很好的理解渲染流程和界面優化;

推薦資料:

 

1.3 事件響應

UI除了展示信息之外,還需要接收並響應用戶的點擊、手勢、搖晃等事件,經過一系列操作後更新展示信息,展示給用戶;正確及時地響應用戶的操作並給 予反饋,是良好用戶體驗的保證。為何Android設備普遍給人的感覺比iOS設備要卡,其中一個主要的原因是iOS系統將響應用戶事件放在主線程的最高 優先順序。

 

1.4 UI系統架構

從整體理解了上述三個方面,你會對UI架構有系統認識。iOS中的UI系統架構如下:

iOS UI Arch

引自WWDC2014 #419 Advanced Graphics and Animations for iOS Apps



2. View

UIView是UIKit中最基本控制項,就如同NSObject基本上是Cocoa庫內所有類的基類一樣,UIView也是UIKit中所有界面控 件的基類。只要你願意,你甚至只用UIView就可以搭建你的App(不過iOS9做了約束,必須設置keyWindow的 rootViewControler)。

一般來說,熟練掌握常用的UIView子類控制項(如UIButton, UIImageView, UILabel等)就足以應付90%的界面編碼需要。但想要編寫出高效、優美的界面代碼,還需要更深入的瞭解。既然要深入,本文假設你對UIView已經 有了初步的瞭解,至少使用寫過幾個完整的頁面;基於此設定下,本文討論聚焦於以下幾點:

1) UIView 與 CALayer:討論UIView背後的CALayer,瞭解CALayer與UIView的關係及渲染流程;

2) Offscreen Render:闡述什麼是Offscreen Render(離屏渲染),以及一些避免離屏渲染的方法;

3) UIResponser:討論UIView和UIViewController的父類UIResponser,分析iOS設備上的事件響應鏈;

4) 設計與實踐:結合本人開發實踐經驗,說明在UIView應用中好的設計實踐規則;

參考:View Programming Guide for iOS

 

2.1 UIView 與 CALayer

我們應該都知道每個UIView都包含了一個CALayer,就算你沒直接看過CALayer,應該也使用過。比如給一個View切個圓角:view.layer.cornerRadius = 5.0f;;加個邊框:view.layer.borderWidth = 1.0f; view.layer.borderColor = [UIColor darkGrayColor].CGColor;,這裡使用的layer就是CALayer。

CALayer是QuartzCore庫內的類,是iOS上最基本的繪製單元;而UIView只是CALyer之上的封裝,更準確的來 說,UIView是CALyer的簡版封裝,加上事件處理的集合類。事件處理我們下一節再討論,這裡的簡版封裝如何理解,為什麼不直接使用 CALayer?

首先,如上一段所述,CALayer是最基本的繪製單元,每一個UIView都有一個CALayer的變數(public var layer: CALayer { get }),UIView的渲染實質就是這個layer的渲染。我們可以看看的類定義,裡面有很多屬性(變數)及方法在中可以找到幾乎一模一樣的對應;如屬性變數framehidden,方法public func convertPoint(p: CGPoint, fromLayer l: CALayer?) -> CGPoint等;但也有更多的屬性方法是UIView所沒有的,這裡就一一列舉了。我們可以看到UIView其實是把常用的介面(屬性和方法)暴露出來了,讓UIView更為易用。

其次,我們知道iOS平臺的Cocoa Touch 是源於OS X平臺的Cocoa), 是在Cocoa的基礎上添加了適用於移動手機設備的手勢識別、動畫等特性;但從底層實現上來說,Cocoa Touch與Cocoa共用一套底層的庫,其中就包括了QuartCore.framework;但QuartCore.framework一開始就是為 OS X設計的,所以其中有部分特性是不適合做移動設備開發的,比如最重要的坐標系統。因此,我們也就不難理解為何UIView/NSView在CALayer 上做了一層封裝。

以上,是UIView於CALayer的主要的關係。

 

2.2 Offscreen Render

當你尚在懵懂未知的開發初期,在寫UIScrollView及其子類(UITableView、UICollectionView)時,一定會遇到 滾動不流暢,經常卡頓的情況;你認真研究代碼,發現你邏輯代碼都放到了非同步線程,主線程做的都是渲染界面的活,為什麼會卡頓?然後你想老手尋求幫助,老手 會讓你去掉圓角、半透明和陰影之類,App又重回絲般順滑;你不知道為什麼,問老手,他可能會很詳細跟你解釋一通,然後你一知半解地點點頭,腦中一片茫 然;較好的情況,也許你依稀記得這麼一個詞:離屏渲染(Offscreen Render)。那到底什麼是Offscreen Render?為什麼Offscreen Render會導致卡頓?

在第一章的1.2節中有提到渲染的流程圖,我們再更深入點,先看看最基本的渲染通道流程:


iOS UI Arch

引自WWDC2014 #419 Advanced Graphics and Animations for iOS Apps

註:iOS的GPU渲染機制是Tile-Based的,而Tile-Based GPU也是現在移動設備的主流;

我們再來看看需要Offscreen Render的渲染通道流程:


iOS UI Arch

引自WWDC2014 #419 Advanced Graphics and Animations for iOS Apps

一般情況下,OpenGL會將應用提交到Render Server的動畫直接渲染顯示(基本的Tile-Based渲染流程),但對於一些複雜的圖像動畫的渲染並不能直接渲染疊加顯示,而是需要根據 Command Buffer分通道進行渲染之後再組合,這一組合過程中,就有些渲染通道是不會直接顯示的;對比基本渲染通道流程和Masking渲染通道流程圖,我們可 以看到到Masking渲染需要更多渲染通道和合併的步驟;而這些沒有直接顯示在屏幕的上的通道(如上圖的 Pass 1 和 Pass 2)就是Offscreen Rendering Pass。

Offscreen Render為什麼卡頓,從上圖我們就可以知道,Offscreen Render需要更多的渲染通道,而且不同的渲染通道間切換需要耗費一定的時間,這個時間內GPU會閑置,當通道達到一定數量,對性能也會有較大的影響;

那哪些情況會Offscreen Render呢?

1) drawRect
2) layer.shouldRasterize = true;
3) 有mask或者是陰影(layer.masksToBounds, layer.shadow*);
4)Text(UILabel, CATextLayer, Core Text, etc)
...

註:layer.cornerRadius,layer.borderWidth,layer.borderColor並不會Offscreen Render,因為這些不需要加入Mask。

還有更多與Offscreen Render以及動畫圖形優化相關的知識,請認真觀看WWDC。

參考:

 

2.3 設計與實踐

以上幾節,對View在開發過程中經常遇到,但並不容易深入理解的概念進行了討論。接下來,我想脫離View的具體概念,談談本人在View設計和開發中的一些實踐經驗;

 

2.3.1 精簡扁平的View層次結構

複雜的View層次結果不僅會影響渲染效率,而且也會造成代碼的臃腫,會造成不可預料的問題並且難以定位;怎麼樣維護一個精簡扁平的View層次結構呢?原則如下:

1) 儘量使用系統原生的控制項;

如實現一個icon跟title上下佈局的按鈕,很多人習慣是使用一個view包含了一個UIButton和一個UILabel。實際上更為推薦的 方式是調整UIButon的contentInset/titleInset/imageInset三個參數來達到這個效果,非常簡單,並且title有 UIButton上的展示方式和特性,如可以設置高亮顏色等;

又比如一個有著複雜一點佈局結構的滾動界面,有些開發者會覺得使用UITableView/UICollectionView實現會比較複雜,有些 效果可能沒辦法達到,就用他們的基類UIScrollView來實現,自己造了一大套的輪子,代碼可能也變得非常複雜;實際上根據我的經驗,通過重寫或者 是內部屬性的調整是完全可以使用UITableView/UICollectionView來達到這個效果,畢竟UITableView /UICollectionView是UIScrollView的子類,功能不會減少,而會更加強大,並且我們還能利用已有的data source和delegate機制,實現設計上的解耦。

其他常見的還有UINavigationBar、UITabBar、UIToolBar等等;


2) 合理添加/刪除動態View;

有些View是動態的,就是偶爾顯示,偶爾隱藏。這類View有兩種處理方式:增刪,或者顯示/隱藏。沒有標準的答案,個人更推薦增刪的處理方式, 即在有需要的時候添加到對應的ContainerView上,在不需要的時候將其刪除。這樣即可以與懶載入結合在一起,而且也能避免兩個動態View的相 互影響,比如TableFooterView,或者是錯誤載入View。但這並不是唯一的方式,假如這個動態View所在的View層級比較簡單,並且需 要動畫進行動態展示,則使用顯示/隱藏也是不錯的處理方式。

 

2.3.2 通用控制項;

每一個程式員都可以建立自己的代碼庫,同理,每一位移動開發程式員都可以建立自己的通用控制項代碼庫。這個庫內的控制項,可以是你自己寫的,也可以是優 秀的第三方開源控制項。建立控制項庫,除了能夠避免重新造輪子,大大提高我們的開發效率,還有更為重要的一點:在運用、改造、重構中掌握介面設計解耦,甚至是 架構的知識和經驗。

每個App的UI設計、交互、佈局和配色往往千差萬別,但總脫離不出移動App這一範疇,也就決定了在某些通用的控制項交互上會保持一致性,以讓用戶 依據自己在移動應用上的使用經驗就能輕鬆快速上手使用,這就是App的移動性。所以通用控制項的適用場景往往是很“通用”的。比如下拉刷新、載入更多、 Tab Bar、提示Tips、載入錯誤重新載入等等。在新的App或者功能模塊上運用這些控制項時,你就會思考怎麼讓控制項更加通用,即不影響舊的邏輯,又能夠適用 新的需求,這對於做界面的架構設計是非常好的鍛煉。

 

2.3.3 合理運用VC在替代View組合複雜界面;

在界面開發過程中,我們常常會遇到複雜的界面,比如多頁界面、多種佈局方式展示多業務的首頁等,但由於很大部分開發者已經對“一屏就是一個VC”這 一初學者的習慣奉為教條,寫出一個龐然大View,再加上複雜的邏輯代碼,這一塊的代碼很可能就演變成了誰都不敢動的禁區。一個VC可以管理多個VC,所 以合理的使用VC來替代View進行複雜界面組合,不僅能夠將複雜界面切分成更小的粒度,邏輯代碼也同步合理劃分,便於維護和重構;而依托VC的機制,還 能View和數據的動態載入管理。

下一章中關於輕VC的討論是這一節知識的拓展。



3. ViewController

上一節關於View的章節已討論了iOS界面機制,這一節則主要是來談談在寫界面過程中的設計問題和基本規範;

ViewController在iOS只是一個非常重要的概念,它是我們在開發界面時最常打交道的模塊,其在一個App中所扮演的角色,View Controller Programming Guide for iOS 中有清晰準確的描述:

1) View Management:管理View;

2) Data Marshalling:管理數據;

3) User Interactions:響應用戶交互;

4) Resource Management:管理資源;

5) Adaptivity:適配不同的屏幕尺寸空間的變化;

可以看到,ViewController有太多的事情要做,這也就導致了ViewController非常容易變得代碼膨脹、邏輯混亂等問題;依照 個人經驗,一個ViewController類的有效代碼超過500行,這個ViewController就會變得難以維護,但實際上在開發過程中,往往 會遇到上1K行,甚至2~3K行的ViewController類;當一個ViewController類達到2~3K行,就意味著其他開發者接手這個模 塊來修改東西,已經無法通過滾動來定位代碼,只能通過搜索;

所以,在進行界面開發時,ViewController需要特別註意模塊設計,將不同的模塊按照邏輯進行一定的拆分,即解耦,又防止ViewController模塊的代碼膨脹。這就是輕VC的理念;

 

3.1 輕VC

輕VC是前兩年非常火的名詞,現在似乎已經成為了一種業界規範或者是慣例。同上所述,一個VC的類,如果有效代碼超過了500行,則表示這個類看是變得臃腫而難以維護;到達800行,只能通過搜索來定位代碼時,重構已勢在必行;

關於輕VC,objc.io的開篇第一章#Issue 1 : Lighter View Controllers,足見這一理念的重要性。掌握輕VC的理念基本上是一個iOS開發者從初級邁向高級必備技能。#Issue 1 : Lighter View Controllers 文中介紹了構建輕VC幾種常見的方式:

1) 將數據源等複雜介面從VC中剝離;

2) 把業務邏輯代碼抽象到Model層;

3) 將複雜View抽象成獨立的類;

4) 使用VC的Containment的特點,將一個VC中邏輯分離的界面模塊剝離成為多個子VC;

想要設計出合理而易於理解和維護的輕VC結構,需要掌握輕VC的知識並有一定實踐經驗。在以下情況下,可以考慮將一個VC設計或者重構成更多模塊更多類的輕VC結構:

1) 如上所述,代碼超過500行時;

2) VC內的View的數據源來自多個不同的地方;

3) VC內有多個複雜的View,需要展示數據實體類較為複雜;

總之,當你感覺你的VC已經變得臃腫,那麼就可嘗試輕VC的實踐,實踐才有收穫。

 

3.2 VC的設計

相對於View關註於佈局和展示,VC更關註設計和管理。本節以一個實例,來簡單介紹在一個完整App中的VC設計。

先來看一個常見的UI結構設計例子:


iOS UI Arch

這個圖應該非常容易理解:最底部是一個側滑抽屜控制項,該抽屜包含了App內容展示的TabBarController和設置的 VC;TabBarController的子Item VC包含了相應業務的List VC,點擊List VC進入到詳情View內;有些詳情VC是使用WebViewController來進行內容的展示。非常簡單,不是麽?接下來說明該設計的洞見:

1) Root ViewController,是整個App內Window的根VC,這是一個生命周期與 App相同的VC,即Window的RootViewController是唯一且一直存在的,需要切換場景則使用這個Root VC控制子VC切換來實現(常見於場景:需要進行強登錄,即登錄之後才能使用的App,登錄成功後從登錄界面切換到主界面,則登錄VC和主界面VC都應該 是Root VC的子VC,受Root VC的控制來進行切換)。這個RootViewController建議是一個UINavigationController,以此保證足夠擴展性,並提 供更為豐富的界面交互選擇。這個Root VC的生命周期與App一致,這樣一些突發的靈活分支界面可以很好的展示在Root VC上,如全局的Loading提示、OpenURL的分支調整等;

2) Main ViewController:主界面,是主要業務展示界面的根界面。該VC與RootVC功 能上會很容易重合在一起,但需要註意的是,該VC並非一直存在,但切換到一些特定分支時,該VC會從Root VC上remove掉,比如前面所說的強登錄App,登錄界面與主界面就會需要進行切換。另外,該VC隔離了主要業務展示界面的VC與Root VC,便於App整體界面風格的改版和重構。比如現在上圖展示的是一個側滑抽屜+TabBar的組合,那到下個版本改版把側滑抽屜去掉,那麼只需要使用 TabBar替換DrawerMenu VC在Main VC中的位置即可,而不會影響到RootVC中其他分支展示出來的界面(如Push等)。

3) TabBarItem ViewController:作為TabBar Controller的子Item VC,通常會設計為NavigationController,用以管理各TabBarItem內的VC棧。 註:如果需要在Push進入二級界面(Detail VC)時隱藏TabBar,只需要設置二級VC的hidesBottomBarWhenPushed = true即可,如果想更加靈活的控制TabBar,例如進到三級頁面的時候顯示出TabBar(這個場景應該很少見),或者你的TabBar是自定義的,可以參考我寫的一個開源控制項MZNavTab

本節所示例的UI結構是一個非常通用的UI結構,市面上除游戲外60%以上的App都是類似的UI交互(統計來源於個人手機),假如你的UI交互與此類似而你的UI結構很混亂的話,不如嘗試下這個UI結構設計。

 

4. MVC、MVP、MVVM

MVC


iOS UI Arch

MVP


iOS UI Arch

MVVM


iOS UI Arch

圖註: 虛線箭頭:表示兩者之間是非強依賴關係。如MVC圖,View與Model一般沒有直接聯繫。

虛線矩形:表示該模塊在對應架構設計中的隱性存在。即一般性架構中並沒有這個角色,但立足於iOS這個平臺,這又是不可或缺的一部分;

本文並不打算將MVC、MVP、MVVM這個幾個通用架構設計模式的概念統統在這裡敘述一遍,上面三個圖基本上能夠很明白地對比出三者之間的差異。也許與你在網上看到的不盡相同,這是因為以上三圖更立足於iOS平臺。

 

4.1 MVC

我們最初看到的MVC設計模式圖可能是這樣的:


iOS UI Arch

引自[MSDN#ASP.NET - Single-Page Applications: Build Modern, Responsive Web Apps with ASP.NET(https://msdn.microsoft.com/en-us/magazine/dn463786.aspx)

而蘋果官方給的MVC的設計模式圖卻是這樣的:


iOS UI Arch

到底哪一副圖才是真正的MVC?我的答案只能是:都是。

MVC從施樂帕克實驗室提出至今,已經應用到各種應用開發領域中:Web App可以用MVC,iOS/Android/Windows客戶端應用也用MVC,Web前端也在用MVC,等等;這些幾乎涵蓋了我們常見的開發領域, 所以MVC其實已經超越了他原本最初的設計,基於所有涉及展示的應用都能套上MVC,只不過不同的平臺在設計上略有差別。而MVP和MVVM,也不過是 MVC的衍生變種,除這兩者之外,還有我們沒怎麼見過的HMVCMVA等。

 

4.2 Model Layer

在討論MVP和MVVM之前,我想先明確一個經常被誤解的概念:Model。由於Model這個詞太通用化,如數據Model,資料庫Model,這就導致了Model這一概念理解差異化,簡單的說,就是被玩壞。拋開其他,我們來看看常見的定義:

Wikipedia的定義

The central component of MVC, the model, captures the behavior of the application in terms of its problem domain, independent of the user interface.[11] The model directly manages the data, logic and rules of the application.

MSDN(https://msdn.microsoft.com/en-us/library/ff649643.aspx)中的定義

Model. The model manages the behavior and data of the application domain, responds to requests for information about its state (usually from the view), and responds to instructions to change state (usually from the controller).

上面兩個定義基本一致:Model,管理應用的行為和數據。

再來看看Apple官方文檔Model-View-Controller的定義

Model Objects

Model objects encapsulate the data specific to an application and define the logic and computation that manipulate and process that data. For example, a model object might represent a character in a game or a contact in an address book. A model object can have to-one and to-many relationships with other model objects, and so sometimes the model layer of an application effectively is one or more object graphs. Much of the data that is part of the persistent state of the application (whether that persistent state is stored in files or databases) should reside in the model objects after the data is loaded into the application. Because model objects represent knowledge and expertise related to a specific problem domain, they can be reused in similar problem domains. Ideally, a model object should have no explicit connection to the view objects that present its data and allow users to edit that data—it should not be concerned with user-interface and presentation issues.

Communication: User actions in the view layer that create or modify data are communicated through a controller object and result in the creation or updating of a model object. When a model object changes (for example, new data is received over a network connection), it notifies a controller object, which updates the appropriate view objects.

雖然Apple的官方文檔是定義Model Objects,但它的含義還是封裝數據以及管理數據相關的邏輯計算;

所以這裡需要明確的一個概念是:在MVC的設計模式中,Model是一個Layer,而不只是一個數據模型(Data Model)類。總體來說,Model Layer 包含了數據模型,以及管理這些數據相關的邏輯計算,如本地數據變化、數據緩存、從網路請求數據等業務邏輯。關於這個問題,還可以參考這篇文章:《iOS應用架構談 view層的組織和調用方案》。 但有一點需要說明:該文章更傾向於從Model Object上思考Model的定義,因為裡面的關於Model的示例是從數據模型中擴展出業務介面;而本人則更傾向於從Model Layer來思考Model,即Model並不限於數據模型,可以是數據管理類(各種Manager)、請求隊列管理等等。

 

4.3 MVP VS MVVM

上一節關於Model Layer中推薦的文章《iOS應用架構談 view層的組織和調用方案》對MVC和MVVM都做了非常詳細的討論,是一篇非常不錯的文章,推薦各位閱讀,那麼本節就來說說MVP,以及我為什麼更傾向於選擇MVP作為App架構設計中的設計框架。

回顧下在本章一開始祭出的MVP以及MVVM兩張圖,兩者之間有什麼不同?

MVVM的VM(View Model)到V(View),比MVP的P(Presenter)到V(View),多了數據綁定。也就是

MVP: 是MVC的變種,其中Model和View的定義與MVC的一致,不同點在於:MVC的Controller是管理一組Model與View之間交互邏 輯,是一個管理者;而Presenter(展示者)則是Model於View之間的連接者,針對特定模塊的View提供對應的格式化的Model數據,將 View中的行為反饋到Model中。所以MVC中的Controller一般會管理一個或多個Model和一個或多個View,而Presenter則 是 M-P-V 一對一,有更細的粒度和更好的解耦。

從MVP的定義,你會發現MVP與MVVM極其相似,Presenter與View Model扮演的角色基本沒有差別,除了前面所說到綁定機制。但綁定機制既有很明顯的強大優點——自動連接View和Model,也有很明顯的缺點——更 高的耦合度,更複雜的代碼邏輯;但讓人感嘆命運無常的是:MVVM隨著ReativeCocoa而在iOS平臺炙手可熱,而iOS平臺上甚少有人提及的 MVP,在Android平臺卻幾乎成了標準(Android5.0引入了數據綁定支持,MVVM會在Android平臺有新的發展)。

我為什麼傾向於MVP?不過是相比於MVVM雙向綁定的便利,我更希望我的App設計中有更強的靈活性和擴展性。沒有完美的架構設計模式,只有適用 於你的App業務場景和團隊的設計模式。比如數據邏輯並不複雜、更註重視覺展示的應用,原始的MVC往往是最優解。所有的MVC衍生出的變種,無非是為了 Solve The Problem。

 

4.4 架構設計模式應用

無論MVC、MVP還是MVVM,都是指導我們進行架構設計的模式,並非可以生搬硬套的;而且在實際的應用中,對於這些設計模式總會有不同的理解, 並且需要根據項目需求進行必要的調整;更為重要的是在我們App的架構設計中,處理好Model-View-Controller之間的關係只是基礎,最 主要的挑戰來自於複雜的業務邏輯和場景,這才是體現一個架構師能力所在。

唐巧前不久寫的一篇文章《被誤解的MVC和被神化的MVVM》對MVC和MVVM的實踐的討論應該是體現了現在移動端主流架構思想,其中對網路請求層、ViewModel 層、Service 層、Storage 層等其它類的提取設計,才決定了一個App架構設計的優劣。

對於架構設計,我準備在下一篇文章,結合本人在iOS/Android兩端的設計經驗,做個深入的討論,並給出自己的設計範例,供各位討論參考。這裡先拋出幾個在架構設計中最常思考的點,作為下一篇文章的引子:

1) 架構是為瞭解耦,越松的耦合就代表越多的份層,但人的思維總是更願意接受直線思維,怎麼解決這個矛盾?

2) 在一個App中,統一(一致)的架構設計能夠讓邏輯代碼更健壯,更有利於團隊成員間的溝通和項目維護,但如何解決其和靈活性之間的矛盾?

3) 架構設計是否只包含邏輯分層?需要設計數據流和多線程麽?

4) 設計模式中的幾大原則;



5 總結

以上四個章節,先從UI整體出發,到剖析UIView幾點重要機制,接著討論怎麼用好VC這個UI中重要的管理角色,最後則漫談了MVC/MVVM /MVP幾個架構設計模式的異同和實踐應用,想通過以點帶面,讓我們在關註了具體實現之後,能夠脫離出來,從俯視下我們App開發更為整體核心的部分。



參考閱讀:

 


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • YARN DistributedShell源碼分析與修改 轉載請註明出處: "http://www.cnblogs.com/BYRans/" <br/ "1 概述" "2 YARN DistributedShell不能滿足當前需求" "2.1 功能需求" "2.2 YARN Distr...
  • 1.概述 我們熟知的資料庫引擎大部分採用靜態數據類型,即列定義的類型定義了值的存儲,並且值要嚴格滿足列的定義,同一列所有值的存儲方式都相同,比如定義了一個列類型為整型 int,不能在該列上輸入'abc'。SQLite的數據類型則採用了動態類型,列定義不能決定值的存儲,值的存儲由值本身決定,因此在.....
  • 首先大家要知道資料庫是由哪三個部分組成的.解析:01.資料庫文件:*.mdf02.次要數據文件:*.ndf03.日誌文件:*.ldf每個資料庫至少要包含兩個文件:一個數據文件和一個日誌文件.數據文件中包含了資料庫的數據和對象,如表,視圖和索引等;日誌文件中包含了用於恢複數據庫所需的信息.創建資料庫時...
  • 當一切正常時,沒有必要特別留意什麼是事務日誌,它是如何工作的。你只要確保每個資料庫都有正確的備份。當出現問題時,事務日誌的理解對於採取修正操作是重要的,尤其在需要緊急恢複數據庫到指定點時。這系列文章會告訴你每個DBA應該知道的具體細節。對於日誌文件的最大日誌吞吐量,我們從存儲架構思路的簡單回顧開始,...
  • 遞歸withmyRecursionas(select*fromrecursionwhereid=1unionallselectr.*frommyRecursionm,recursionrwherem.id=r.pid)select*frommyRecursionPs:unionall不去重求並集很多...
  • 這裡使用的是mysql Ver 14.14 Distrib 5.6.19, for Linux (i686) using EditLine wrapper一、mysql目錄文件ibdata1:系統表空間 包含數據字典、回滾日誌/undolog等(insert buffer segment/doubl...
  • Oracle 資料庫中 SQL 分析的主要優勢Oracle 資料庫中分析功能和特性提供以下主要優勢:1. 提高開發人員產能 — 開發人員可以通過更清晰、更簡潔的 SQL 代碼執行複雜分析。現在可以使用一條 SQL 語句表示覆雜任務,編寫和維護速度更快、效率更高。 2. 提高查詢速度 — 資料庫中分析...
  • 色溫色溫是表示光源光譜質量最通用的指標。 GPUImage中我們通過GPUImageWhiteBalanceFilter來實現 頂點著色uniform sampler2D inputImageTexture;varying highp vec2 textureCoordinate; unif...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...