如果您是具有高級技能且經(jīng)歷過大量iOS項目的iOS開發(fā)人員,您一定會知道選擇合適的設(shè)計模式非常重要。它可以幫助您的項目順利運行,并使其更具可讀性,靈活性和可重用性.
基于這些經(jīng)驗,在本Swift教程中,我們將討論所有iOS設(shè)計模式,以便您高度概述iOS應(yīng)用程序開發(fā)中可能和常見的內(nèi)容。

- iOS設(shè)計模式簡介
我正在建造房子,你必須有一個詳細設(shè)計的計劃。如果計劃質(zhì)量差,在建設(shè)時,工人將遇到困難。房子肯定不會很漂亮或安全。這也適用于任何iOS項目。事實上,成功運行的編程代碼并不困難,但掌握MVC之外的漂亮架構(gòu)工藝將為您的應(yīng)用程序設(shè)置成功和可擴展性。
當客戶端,產(chǎn)品經(jīng)理或用戶發(fā)生更改或更新時,將出現(xiàn)平庸體系結(jié)構(gòu)的問題。如果沒有可靠的初始設(shè)計,構(gòu)建新功能會變得很難 如果沒有使用好的架構(gòu)模式,那么在不破壞當前代碼庫的情況下,您將很難進行任何進一步的修改。此外,當您的團隊中的許多成員必須更改同一個大文件中的代碼時,由于合并沖突,您會發(fā)現(xiàn)自己遇到了大麻煩。您的團隊的工作效率會顯著降低。
好的,不再談?wù)摓槭裁次覀儜?yīng)該探索我們可用的所有iOS設(shè)計模式。我們已經(jīng)談過它們了。今天,我們來看看四種最流行的iOS設(shè)計模式:
MVC:模型 - 視圖 - 控制器
MVP:模型 - 視圖 - 演示者
MVVM:模型 - 視圖 - 視圖模型
VIPERS:View-Interactor-Presenter-Entity(aka Model)-Router
2.模型和視圖之間的關(guān)系
您可能想知道為什么視圖模型總是出現(xiàn)在所有模式中。是啊,你說得對。對于每個應(yīng)用程序,這兩個部分起著重要作用:
- 圖形用戶界面(也稱為視圖):顯示數(shù)據(jù)并接收用戶的交互,例如輕擊手勢,長按,搖動等。
- 數(shù)據(jù)(也稱為模型):存儲為應(yīng)用程序狀態(tài)的實際用戶信息(在服務(wù)器或iPhone上)。
在一個簡單的應(yīng)用程序中,我們可以將模型中的信息直接顯示在屏幕上。對于UI的任何更改,我們會更新我們的模型,但并非全部。您的項目越大,應(yīng)用程序邏輯就越復雜。我們必須驗證,格式化,轉(zhuǎn)換數(shù)據(jù),甚至從服務(wù)器獲取數(shù)據(jù),然后在數(shù)據(jù)發(fā)生變化時立即更新視圖。
在這方面,iOS設(shè)計模式的一般解決方案是通過將組件分成較小的組件來減少組件之間的相互依賴性,并且責任有限。在這篇Swift文章中,我們將弄清楚他們是如何解決這個問題的。我們將制作一個簡單的應(yīng)用程序并應(yīng)用所有iOS體系結(jié)構(gòu)模式(并向您解釋,同時向您展示Swift代碼示例),而不是引入一堆復雜和抽象的理論(您可以在Google上輕松搜索)它更容易理解。
注意:由于本文僅側(cè)重于分析模式,因此我們不會詳細介紹功能分析。
您可以在此處下載入門項目。

- MVC
現(xiàn)在讓我們首先深入了解MVC。我們來看看下面的Swift代碼:
var yourOrder: Order?
override func viewDidLoad() {
super.viewDidLoad()
dataInitialization()
updateUIBy(yourOrder)
}
@IBAction func didTapOnDecreaseButton(_ sender: Any) {...}
@IBAction func didTapOnIncreaseButton(_ sender: Any) {...}
@IBAction func didTapOnBuyButton(_ sender: Any) {...}
private func dataInitialization() {
yourOrder = Order(title: "", quantity: 0, price: 0.0)
}
private func updateUIBy(_ order: Order?) {...}
}
extension ViewController: UITableViewDelegate {
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {...}
}
這看起來就像一個普通的視圖控制器,對嗎?我們的過程如下:
1。創(chuàng)建一個名為yourOrder的變量。這將是我們的模型。我們還有 dataInitialization函數(shù)初始化狀態(tài)。
2.創(chuàng)建一個名為updateUIBy的函數(shù) ,根據(jù)yourOrder的更改來更新UI 。因此,您可以看到Controller在模型更改時立即更新了UI
3.請注意以下功能:
didTapOnDecreaseButton
didTapOnIncreaseButton
tableView(_ tableView:UITableView,didSelectRowAt indexPath:IndexPath)
這些是用戶與View交互的位置,在Controller收到新數(shù)據(jù)后,它將通過調(diào)用 updateUIBy函數(shù)更新視圖層來更新數(shù)據(jù)模型。讓我們看看其中一個是什么:
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
yourOrder?.setTitle(templates[indexPath.row].title)
yourOrder?.setPrice(templates[indexPath.row].price)
updateUIBy(yourOrder)
}
現(xiàn)在讓我們將下圖中的架構(gòu)與我們的項目進行比較

我們將: View < - > Storyboard文件, Controller < - > ViewController文件, Model:Regular文件。
如上所述,控制器將扮演管理角色,在模型和視圖之間保持聯(lián)系。根據(jù)模型的變化,它將決定視圖需要顯示的內(nèi)容。如果需要,它甚至會改變視圖。在此處下載完整的源代碼以獲取更多詳細信息 您將更加了解我們在此處所描述的內(nèi)容。讓我們來看看這個應(yīng)用程序吧。


它看起來很不錯,但正如你所看到的,ViewController幾乎可以做任何事情。在實際項目中,它還必須處理視圖周圍的其他邏輯,例如動畫,顯示/隱藏子視圖,導航,傳遞數(shù)據(jù),記錄等,以及數(shù)據(jù)模型層的邏輯。這將使ViewController變得越來越大,這也是人們經(jīng)常調(diào)用MVC Massive View Controller的原因。它最終跟隨舊設(shè)計模式的錯誤腳步。讓我們繼續(xù)下一個模式,看看我們是否可以更好地設(shè)計iOS應(yīng)用程序。
- MVP
好吧,讓我們開始使用Model - View - Presenter設(shè)計模式。首先,我們創(chuàng)建一個名為OrderViewProtocol的協(xié)議 和一個名為OrderViewPresenter的類, 如下所示:
protocol OrderViewProtocol: class {
func updateModel(order: Order?)
func updateUI(order: Order?)
}
class OrderViewPresenter {
private var order: Order?
private weak var delegate: OrderViewProtocol?
init(order: Order?, delegate: OrderViewProtocol?) {
self.order = order
self.delegate = delegate
self.updateUIByOrder()
}
func setInformation(_ title: String, price: Double) {...}
func increaseQuantity(_ currentQuantity: String?) {...}
func decreaseQuantity(_ currentQuantity: String?) {...}
func updateUIByOrder() {
delegate?.updateModel(order: order)
delegate?.updateUI(order: order)
}
}
然后我們調(diào)整我們的ViewController,如下所示:
var yourOrder: Order?
var orderViewPresenter: OrderViewPresenter?
override func viewDidLoad() {
super.viewDidLoad()
dataInitialization()
orderViewPresenter = OrderViewPresenter(order: yourOrder, delegate: self)
}
@IBAction func didTapOnDecreaseButton(_ sender: Any) {
orderViewPresenter?.decreaseQuantity(quantityLabel.text)
}
@IBAction func didTapOnIncreaseButton(_ sender: Any) {
orderViewPresenter?.increaseQuantity(quantityLabel.text)
}
private func dataInitialization() {...}
private func updateUIBy(_ order: Order?) {...}
}
extension ViewController: UITableViewDelegate {
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
orderViewPresenter?.setInformation(templates[indexPath.row].title, price: templates[indexPath.row].price)
}
}
在分析代碼之前,我們需要知道Presenter的角色是什么。它將使用委托處理用戶交互和UI更新等邏輯。當有任何變化時,它還負責更新模型。所以,我們的流程如下。這里有兩個很大的不同點。你還記得MVC模式中的這三個函數(shù)嗎?
* didTapOnDecreaseButton
* didTapOnIncreaseButton
* tableView(_ tableView:UITableView,didSelectRowAt indexPath:IndexPath)
是的,在MVC模式中,我們使用了一些代碼行來更新我們的模型和UI。但是現(xiàn)在呢?只有一行代碼。我們需要做的是將UI更改中的所有信息傳遞給演示者。演示者將完成剩下的工作。我們來看看這個

此模式中的ViewController被視為視圖層的一部分。它只在UI上顯示/顯示數(shù)據(jù)。就這樣。這顯著減少了ViewController的工作量,并且只需要通過委托模式根據(jù)模型的最新更改來更新用戶界面。
extension ViewController: OrderViewProtocol {
func updateModel(order: Order?) {
yourOrder = order
}
func updateUI(order: Order?) {
updateUIBy(order)
}
}
現(xiàn)在,請在此處下載完整的源代碼并運行該應(yīng)用程序。您將看到結(jié)果完全相同,但現(xiàn)在我們有更多的組件,具有更具體的職責,這是我們在編寫iOS代碼時需要牢記的最重要的設(shè)計原則。
5. MVVM
可以說MVVM模式是iOS開發(fā)者社區(qū)目前最受歡迎的架構(gòu)之一。與MVP架構(gòu)中的Presenter一樣,ViewModel看起來像是連接View和Model的東西。但它仍然有一些關(guān)鍵的不同之處:
- ViewModel類可用于多個視圖,因為它不需要了解有關(guān)視圖的任何信息。
- ViewModel類通過綁定數(shù)據(jù)或Observer設(shè)計模式與View類進行通信。
由于這一點,當我們聽到名稱MVVM時,我們立即想到了反應(yīng)式編程,反之亦然。它成為近年來發(fā)展非常強大的現(xiàn)代有效模式。請注意,如果您不在MVVM中使用綁定數(shù)據(jù),只需將ViewModel用作處理數(shù)據(jù)或更新視圖等類的類,它就會使ViewModel看起來像Presenter,它會將架構(gòu)帶回MVP。
6. VIPER
要談?wù)搃OS VIPER模式,我們需要詳細分析它,否則,它會感到非常模糊和混亂。因此,在本節(jié)中,我們將討論VIPER的概述,并將在不久的將來寫一篇關(guān)于此模式的單獨文章。
在上面的模式中,這些中間層(例如Presenter或ViewModel)的負擔也很大,當它需要處理動畫或?qū)Ш降纫晥D的邏輯(特別是導航流和屏幕之間的數(shù)據(jù)傳遞)以及模型的邏輯。讓我們看看VIPER如何使導航更有條理。

如您所見,在VIPER中,每個部分都執(zhí)行一項特定任務(wù)。
- 觀點:這里沒有任何變化。該視圖負責將用戶操作發(fā)送到中間層并顯示他們收到的任何內(nèi)容。
- Interactor:這是這種模式中最重要的部分。這是解決業(yè)務(wù)邏輯的地方。
- 演示者:與演示者在MVP中的角色或ViewModel在MVVM中的角色一樣,演示者將處理從用戶的交互中接收的數(shù)據(jù)。它會將結(jié)果發(fā)送到視圖層。它還要求路由器輸入導航內(nèi)容。
- 實體:實體就像往常一樣。
- 路由器:VIPER部件將通過Router / Wireframe相互連接。它保留所有參考,并負責導航部分。
正如您所看到的,此模式為每個特定類細分了許多任務(wù)。通過將關(guān)注點分離到自己的組件中,我們實現(xiàn)了更具可擴展性的架構(gòu)。另一個好處是 ,不同層之間的大多數(shù)通信都是通過委托進行的,因此它們非常獨立,可以輕松替換和擴展。這種iOS設(shè)計模式大量利用Swift協(xié)議,這使其成為適合Swift編程語言的完美架構(gòu)。
7.結(jié)論
最后,我們?yōu)g覽了最流行的iOS設(shè)計模式。 它們對您的應(yīng)用程序意味著很多,希望本文可以幫助您更好地理解它們。事實上,模式的選擇取決于團隊的能力或項目的復雜性。最后但并非最不重要的是,不要只是在一個類中放入一堆代碼,因為它在那個時候更容易,即使它與它的責任相沖突。在寫下代碼之前一定要認真思考。
在完成之前,我們面臨著挑戰(zhàn)。在MVVM部分,我們沒有示例代碼,我們將為您提供這個有趣的部分。
請與您的社區(qū)分享這篇文章,以幫助我們傳播世界。快樂的編碼!