作為iOS整個項目的核心App delegate,隨著項目的逐漸變大,會變得越來越臃腫,一不小心代碼就過了千行.
大型項目的App delegate體積會大到什么程度呢?我們可以參考下國外2億多月活的Telegram的 App delegate.是不是嚇一跳,4千多行.看到這樣的代碼是不是很想點擊左上角的x.
是時候該給App delegate解耦了,目標(biāo):
每個功能的配置或者初始化都分開,各自做各自的事情.App delegate要做到只需要調(diào)用就好了.
下面來談?wù)勅绾卫脙煞N設(shè)計模式實現(xiàn):
1.命令模式
命令模式: 發(fā)送方發(fā)送請求,然后接收方接受請求后執(zhí)行,但發(fā)送方可能并不知道接受方是誰,執(zhí)行的是什么操作,這樣做的好處是發(fā)送方和接受方完全的松耦合,大大提高程序的靈活性.
1. 定義好協(xié)議,把相關(guān)初始化配置代碼分類
protocol Command {
func execute()
}
struct InitializeThirdPartiesCommand: Command {
func execute() {
// 第三方庫初始化代碼
}
}
struct InitialViewControllerCommand: Command {
let keyWindow: UIWindow
func execute() {
// 根控制器設(shè)置代碼
}
}
struct InitializeAppearanceCommand: Command {
func execute() {
// 全局外觀樣式配置
}
}
struct RegisterToRemoteNotificationsCommand: Command {
func execute() {
// 遠程推送配置
}
}
2. 管理者
final class StartupCommandsBuilder {
private var window: UIWindow!
func setKeyWindow(_ window: UIWindow) -> StartupCommandsBuilder {
self.window = window
return self
}
func build() -> [Command] {
return [
InitializeThirdPartiesCommand(),
InitialViewControllerCommand(keyWindow: window),
InitializeAppearanceCommand(),
RegisterToRemoteNotificationsCommand()
]
}
}
3. App delegate調(diào)用
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
StartupCommandsBuilder()
.setKeyWindow(window!)
.build()
.forEach { $0.execute() }
return true
}
使用命令模式的好處是,如果要添加新的配置,設(shè)置完后只要加在StartupCommandsBuilder中就可以了.App delegate中不需要添加任何內(nèi)容.
但這樣做只能將didFinishLaunchingWithOptions中的代碼解耦,App delegate中的其他方法怎樣解耦呢?
2.組合模式
組合模式: 可以將對象組合成樹形結(jié)構(gòu)來表現(xiàn)"整體/部分"層次結(jié)構(gòu). 組合后可以以一致的方法處理個別對象以及組合對象.
這邊我們給App delegate每個功能模塊都設(shè)置一個子類,每個子類可以根據(jù)所需定義App delegate的方法.
1. 每個子模塊實現(xiàn)各自的功能
// 推送
class PushNotificationsAppDelegate: AppDelegateType {
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
print("推送配置")
return true
}
func application(_ application: UIApplication, didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data) {
print("推送相關(guān)代碼...")
}
// 其余方法
}
// 外觀樣式
class AppearanceAppDelegate: AppDelegateType {
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
print("外觀樣式配置")
return true
}
}
// 控制器處理
class ViewControllerAppDelegate: AppDelegateType {
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
print("根控制器設(shè)置代碼")
return true
}
}
// 第三方庫
class ThirdPartiesConfiguratorAppDelegate: AppDelegateType {
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
print("第三方庫初始化代碼")
return true
}
func applicationDidEnterBackground(_ application: UIApplication) {
print("ThirdPartiesConfiguratorAppDelegate - applicationDidEnterBackground")
}
func applicationDidBecomeActive(_ application: UIApplication) {
print("ThirdPartiesConfiguratorAppDelegate - applicationDidBecomeActive")
}
}
2. 管理者
typealias AppDelegateType = UIResponder & UIApplicationDelegate
class CompositeAppDelegate: AppDelegateType {
private let appDelegates: [AppDelegateType]
init(appDelegates: [AppDelegateType]) {
self.appDelegates = appDelegates
}
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
appDelegates.forEach { _ = $0.application?(application, didFinishLaunchingWithOptions: launchOptions) }
return true
}
func application(_ application: UIApplication, didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data) {
appDelegates.forEach { _ = $0.application?(application, didRegisterForRemoteNotificationsWithDeviceToken: deviceToken) }
}
func applicationDidEnterBackground(_ application: UIApplication) {
appDelegates.forEach { _ = $0.applicationDidEnterBackground?(application)
}
}
func applicationDidBecomeActive(_ application: UIApplication) {
appDelegates.forEach { _ = $0.applicationDidBecomeActive?(application)
}
}
}
3. App delegate調(diào)用
@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {
var window: UIWindow?
let appDelegate = AppDelegateFactory.makeDefault()
enum AppDelegateFactory {
static func makeDefault() -> AppDelegateType {
return CompositeAppDelegate(appDelegates: [
PushNotificationsAppDelegate(),
AppearanceAppDelegate(),
ThirdPartiesConfiguratorAppDelegate(),
ViewControllerAppDelegate(),
]
)
}
}
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
_ = appDelegate.application?(application, didFinishLaunchingWithOptions: launchOptions)
return true
}
func application(_ application: UIApplication, didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data) {
appDelegate.application?(application, didRegisterForRemoteNotificationsWithDeviceToken: deviceToken)
}
func applicationDidBecomeActive(_ application: UIApplication) {
appDelegate.applicationDidBecomeActive?(application)
}
func applicationDidEnterBackground(_ application: UIApplication) {
appDelegate.applicationDidEnterBackground?(application)
}
}
在App delegate解耦中相比命令模式,使用組合模式的可自定義程度會更高一點.
本文收錄于 SwiftTips