AppDelegate解耦

作為iOS整個項目的核心App delegate,隨著項目的逐漸變大,會變得越來越臃腫,一不小心代碼就過了千行.

大型項目的App delegate體積會大到什么程度呢?我們可以參考下國外2億多月活的TelegramApp 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

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容