跳到主要内容

减轻 AppDelegate 的负担

· 阅读需 5 分钟

命令模式

命令模式 以对象来代表单一动作和事件,并把对象叫做命令。命令封装了所有参数,命令的调用者无需了解命令做了什么。

我们给每一个 app delegate 责任定义一个命令,命令的名称表明了目的。

protocol Command {
func execute()
}

struct InitializeThirdPartiesCommand: Command {
func execute() {
// 第三库初始化
}
}

struct InitailizeViewControllerCommand: Command {
let keyWindow: UIWindow

func execute() {
keyWindow.rootViewController = UIViewController()
}
}

struct InitailizeAppearanceCommand: Command {
func execute() {
// 设置 UIAppearance
}
}

struct RegisterToRemoteNotificationCommand: Command {
func execute() {
// 注册远程通知
}
}

接下来,我们定义一个StartupCommandsBuilder来封装命令的创建细节。AppDelegate 调用 builder 来初始化命令,然后触发命令。

// MARK: - Builder

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()
]
}
}

// MARK: - App Delegate

@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {
var window: UIWindow?

func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
StartupCommandsBuilder()
.setKeyWindow(window!)
.build()
.forEach { $0.execute() }

return true
}
}

新的命令可以直接添加到 builder,而不需要修改AppDelegate

组合模式

组合模式把一组相似的对象当做一个单一对象处理,依据树形结构来组合对象。这种模式创建了一个包含自己对象组的类,提供了修改相同对象组的方式。

iOS 里面最显著的用法就是UIViewsubViews

typealias AppDelegateType = UIResponder & UIApplicationDelegate

class CompositeAppDelegate: AppDelegate {
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) }
}
}

然后,实现AppDelegate

class PushNotificationsAppDelegate: AppDelegateType {
func application(_ application: UIApplication, didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data) {
// Registered successfully
}
}

class StartupConfiguratorAppDelegate: AppDelegateType {
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
// Perform startup configurations, e.g. build UI stack, setup UIApperance
return true
}
}

class ThirdPartiesConfiguratorAppDelegate: AppDelegateType {
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
// Setup third parties
return true
}
}

我们定义一个工厂类AppDelegateFactory实现创建 App Delegate 的逻辑。我们的主AppDelegate创建了子AppDelegate组合,然后传递方法给它们。

enum AppDelegateFactory {
static func makeDefault() -> AppDelegateType {
return CompositeAppDelegate(appDelegates: [PushNotificationsAppDelegate(), StartupConfiguratorAppDelegate(), ThirdPartiesConfiguratorAppDelegate()])
}
}

@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {

var window: UIWindow?
let appDelegate = AppDelegateFactory.makeDefault()

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)
}
}

中介者模式

中介者模式 使用一个中介对象来封装一系列的对象交互。

我们定义一个中介者AppLifecycleMediator,用它来传递UIApplication的生命周期事件给隐藏的监听者。这些监听者必须实现协议AppLifecycleListener

protocol AppLifecycleListener {
func onAppWillEnterForground()
func onAppDidEnterBackground()
func onAppDidFinishLaunching()
}

class AppLifecycleMediator: NSObject {
private let listeners: [AppLifecycleListener]

init(listeners: [AppLifecycleLister]) {
self.listeners = listeners
super.init()
subscribe()
}

deinit {
NotificationCenter.default.removeObserver(self)
}

private func subscribe() {
NotificationCenter.default.addObserver(self, selector: #selector(onAppWillEnterForeground), name: .UIApplicationWillEnterForeground, object: nil)
NotificationCenter.default.addObserver(self, selector: #selector(onAppDidEnterBackground), name: .UIApplicationDidEnterBackground, object: nil)
NotificationCenter.default.addObserver(self, selector: #selector(onAppDidFinishLaunching), name: .UIApplicationDidFinishLaunching, object: nil)
}

@objc private func onAppWillEnterForeground() {
listeners.forEach { $0.onAppWillEnterForeground() }
}

@objc private func onAppDidEnterBackground() {
listeners.forEach { $0.onAppDidEnterBackground() }
}

@objc private func onAppDidFinishLaunching() {
listeners.forEach { $0.onAppDidFinishLaunching() }
}
}

extension AppLifecycleMediator {
static func makeDefaultMediator() -> AppLifecycleMediator {
let listener1 = ...
let listener2 = ...
return AppLifecycleMediator(listeners: [listener1, listener2])
}
}

现在,在AppDelegate里面只需要一行代码就行了:

@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {
var window: UIWindow?

let mediator = AppLifecycleMediator.makeDefaultMediator()

func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
return true
}
}