對於iOS開發而言 始終沒法繞開UIKit
這個框架, 加之SwiftUI
並不成熟, 因此你懂的, 而UIKit
框架就是基於的MVC
的設計模式, 因此這也是爲何MVC
是蘋果官方推薦的設計模式.git
一. 官方推薦
這個標籤確定是有必定份量的.github
二. 在一個基於MVC的框架上強行使用MVVM或MVP的設計模式, 不是不能夠, 但總有些地方會差強人意, 當你使用各類知名框架時就會體會到這種感受, 固然你能夠選擇忽略不計, 但它們確實存在.swift
三. 簡單, 很是的簡單, 沒有學習成本, 是個開發者就懂, 基本沒有"交流"障礙. 越簡單越利於維護(這也是我比較推崇的開發風格 一切從簡).設計模式
四. 可擴展性強, 由於足夠通用, 因此在MVC基礎上能夠根據具體業務須要轉變成其餘設計模式, 總的來講 整個項目的基礎設計模式仍是MVC, 根據不一樣業務模塊狀況能夠再使用最合適的設計模式.框架
沒錯 臃腫的C層代碼. 因此不少優化方案都是圍繞這點展開的, 我們也不例外.ide
UIViewController
在實際開發中會遇到不少問題, 這裏咱們只說View相關的問題.佈局
按照蘋果的設計理念: UIViewController
對應MVC
的C
, UIView
對應MVC
的V
, XXXModel
對應MVC
的M
.學習
但尷尬的是 咱們使用UIViewController
時 難免會有不少View的處理在其中, 純代碼的方式還好一些, 能夠經過封裝自定義View類來解決, Storyboard
和Xib
的方式就尤其明顯了.優化
純代碼:ui
自定義View類來編寫視圖相關的代碼, 能夠將V的處理從UIViewController
中分離出去, 可是難免要在UIViewController
中再次編寫初始化 佈局等代碼. 試想每一個UIViewController
都要寫一遍某個View的初始化 添加父視圖 佈局等.
Storyboard或XIB:
拖線連接的控件一般會在UIViewController
中, 常常見到UIViewController
中拖了一堆視圖控件對象. 固然除了拖進來還要寫一下其餘視圖相關的代碼. 也有使用自定義View類來承載全部拖線連接的控件對象 和上面純代碼的方式差很少.
一樣的困境: 在UIViewController
中view的類型永遠都是UIView
, 上面兩種方式遇到的問題同樣, 須要作類型轉換才能訪問到自定義View類中的屬性和方法, 這無疑是很麻煩的.
ViewController
基類, 並保證基類的乾淨, 這是一個很好的習慣)class ViewController<Container: UIView>: UIViewController {
var container: Container { view as! Container }
override func loadView() {
super.loadView()
if view is Container {
return
}
view = Container()
}
}
複製代碼
class HomeController: ViewController<HomeView> {
override func viewDidLoad() {
super.viewDidLoad()
}
}
複製代碼
container
屬性直接訪問上面聲明的自定義View類型對象, 固然你也能夠改成其餘名字class XXXXController: ViewController<XXXXView> {
// CODE
override func viewDidLoad() {
super.viewDidLoad()
// CODE
container.xxxx()
}
}
複製代碼
純代碼:
class XXXXView: UIView {
private lazy var titleLabel = UILabel()
private lazy var iconImageView = UIImageView()
override init(frame: CGRect) {
super.init(frame: frame)
titleLabel.textColor = .black
titleLabel.font = .systemFont(ofSize: 13, weight: .semibold)
iconImageView.contentMode = .scaleAspectFill
addSubview(titleLabel)
addSubview(iconImageView)
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
override func layoutSubviews() {
super.layoutSubviews()
titleLabel.frame = .init(x: 100, y: 100, width: 100, height: 40)
iconImageView.frame = .init(x: 100, y: 100, width: 100, height: 100)
}
func set(title: String) {
titleLabel.text = title
}
func set(image: UIImage) {
iconImageView.image = image
}
}
複製代碼
class XXXXController: ViewController<XXXXView> {
private let model = XXXXModel()
// CODE
override func viewDidLoad() {
super.viewDidLoad()
// CODE
container.set(title: model.title)
container.set(image: model.image)
}
}
複製代碼
let controller = XXXXController()
present(controller, animated: true)
複製代碼
Storyboard或XIB:
設置Controller類:
設置View類:
向View中拖線連接:
在Controller中爲視圖設置數據:
方法簡單, 很好的解決了上面提到的這些問題, 使Controller與View的分離更加優雅.
class HomeController: ViewController<HomeView> { }
複製代碼
頭部的聲明能夠直觀的看到Controller的View類型, 可讀性強.
因明確了類型 調用更加順暢天然, 省去了多餘的類型轉換代碼.
使 Controller 能夠更專一於Model與View的協調和調用, 職責更明確.
截止如今, 這個方法我本身已經使用2年了 其中也經歷了幾個項目的洗禮, 仍是沒什麼問題的, 你們若是感興趣能夠放心採納.
若是你有更好的想法 歡迎評論交流.