UIAppDelegate解耦

1.OC版的UIAppDelegate 解耦

oc版本的解耦demo有很多,大家可以google出来很多的方法。这里我推荐使用豆瓣的FRDModuleManager。推荐阅读这篇文章http://www.cocoachina.com/articles/17938。简单的说一下使用方法。

1.1 加载所有模块,文件从 plist中获取,将不同的模块填写到 plist 文件中。

1567072713370.jpg

1.2 在 UIApplicationDelegate 各方法中留下钩子

  - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
  NSString* plistPath = [[NSBundle mainBundle] pathForResource:@"ModulesRegister" ofType:@"plist"];
    FRDModuleManager *manager = [FRDModuleManager sharedInstance];
    [manager loadModulesWithPlistFile:plistPath];

    [manager application:application didFinishLaunchingWithOptions:launchOptions];

    return YES;
  }

  - (void)applicationWillResignActive:(UIApplication *)application {
    [[FRDModuleManager sharedInstance] applicationWillResignActive:application];
  }

  - (void)applicationDidEnterBackground:(UIApplication *)application {
    [[FRDModuleManager sharedInstance] applicationDidEnterBackground:application];
  }

  - (void)applicationWillEnterForeground:(UIApplication *)application {
    [[FRDModuleManager sharedInstance] applicationWillEnterForeground:application];
  }

  - (void)applicationDidBecomeActive:(UIApplication *)application {
    [[FRDModuleManager sharedInstance] applicationDidBecomeActive:application];
  }

  - (void)applicationWillTerminate:(UIApplication *)application {
    [[FRDModuleManager sharedInstance] applicationWillTerminate:application];
  }

1.3 在特定模块,根据需求完成注册即可,比如以下为PushModule的模块

//这是一个遵守了FRDModule协议的模块PushModule.h
@interface PushModule : NSObject<FRDModule>

@end

//PushModule.m
 (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
    NSLog(@"%@  PushModule", NSStringFromSelector(_cmd));
    
    [self zxc_configurationAccount:launchOptions];
    
    return YES;
}

- (void)applicationWillResignActive:(UIApplication *)application
{
  NSLog(@"%@  PushModule", NSStringFromSelector(_cmd));
}

- (void)applicationDidEnterBackground:(UIApplication *)application
{
  NSLog(@"%@  PushModule", NSStringFromSelector(_cmd));
}

- (void)applicationWillEnterForeground:(UIApplication *)application
{
  NSLog(@"%@  PushModule", NSStringFromSelector(_cmd));
}

- (void)applicationDidBecomeActive:(UIApplication *)application
{
  NSLog(@"%@  PushModule", NSStringFromSelector(_cmd));
}

- (void)applicationWillTerminate:(UIApplication *)application
{
  NSLog(@"%@  PushModule", NSStringFromSelector(_cmd));
}

-(BOOL)application:(UIApplication *)application handleOpenURL:(NSURL *)url{
    
    NSLog(@"11111");
    return  [[UMSocialManager defaultManager] handleOpenURL:url];
}

1.4 这样就可以了。具体的请看demo

2.swfit版的UIAppDelehate解耦

swift的解耦也可以使用FRDModuleManager,但是自己觉得不是很好。所以在不停的学习中发现了 Massive App Delegate,使用了以后觉得不错。,下面说说具体的使用吧。给自己记个笔记

2.0 命令设计模式 启动时来初始化各种命令(比如 第三方库的初始化,根视图控制器等)
  var window: UIWindow?

    let mediator = AppLifecycleMediator.makeDefaultMediator()

    let appDelegate = AppDelegateFactory.makeDefault()

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

        _ = appDelegate.application?(application, didFinishLaunchingWithOptions: launchOptions)

        return true
    }

//启动命令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()
        ]
    }
}
protocol Command {
    func execute()
}
////第三方在这里初始化
struct InitializeThirdPartiesCommand: Command {
    func execute() {
        // Third parties are initialized here
    }
}
////在这里初始化根视图控制器
struct InitialViewControllerCommand: Command {
    let keyWindow: UIWindow

    func execute() {
        // Pick root view controller here
        keyWindow.rootViewController = ViewController()
    }
}
//设置UIAppearance 全局设置 通过UIAppearance设置一些UI的全局效果,这样就可以很方便的实现UI的自定义效果又能最简单的实现统一界面风格
struct InitializeAppearanceCommand: Command {
    func execute() {
        // Setup UIAppearance
        UINavigationBar.appearance().tintColor = .black
        UISearchBar.appearance().tintColor = .red
    }
}
////在这里注册远程通知
struct RegisterToRemoteNotificationsCommand: Command {
    func execute() {
        // Register for remote notifications here
    }
}
2.1 复合设计模式 让复合和叶子委托每个都有一个责任。类似工厂一样复合了整个的AppDelegate,然后分发给相应的子叶的AppDelegate。(比如推送通知AppDelegate)
var window: UIWindow?

    let mediator = AppLifecycleMediator.makeDefaultMediator()

    let appDelegate = AppDelegateFactory.makeDefault()

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

        _ = appDelegate.application?(application, didFinishLaunchingWithOptions: launchOptions)

        return true
    }
//AppDelegate工厂
//这些对象封装了触发自身所需的所有参数
enum AppDelegateFactory {
    static func makeDefault() -> AppDelegateType {
        return CompositeAppDelegate(appDelegates: [PushNotificationsAppDelegate(), StartupConfiguratorAppDelegate(), ThirdPartiesConfiguratorAppDelegate()])
    }
}

typealias AppDelegateType = UIResponder & UIApplicationDelegate

//复合AppDelegate
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) }
    }
}

//推送通知AppDelegate
class PushNotificationsAppDelegate: AppDelegateType {
    func application(_ application: UIApplication, didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data) {
        // Registered successfully
        
    }
}

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

//第三方配置程序AppDelegate
class ThirdPartiesConfiguratorAppDelegate: AppDelegateType {
    func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
        // Setup third parties
        return true
    }
}
2.2 中介者模式 将UIApplication的生命周期通知底下的监听者。如定义AppLifecycleMediator将UIApplication的生命周期通知底下的监听者,这些监听者必须遵循AppLifecycleListener协议,如果需要监听者要能扩展新的方法。
// MARK: - AppLifecycleListener
protocol AppLifecycleListener {
    func onAppWillEnterForeground()
    func onAppDidEnterBackground()
    func onAppDidFinishLaunching()
}

extension  AppLifecycleListener {
    func onAppWillEnterForeground() {}
    func onAppDidEnterBackground() {}
    func onAppDidFinishLaunching() {}
}

//相应的通知应该做的事
class VideoListener: AppLifecycleListener {
    func onAppDidEnterBackground() {
        //停止视频播放
    }
}

class SocketListener: AppLifecycleListener {
    func onAppWillEnterForeground() {
        //开启长连接
    }
}

// MARK: - Mediator
//将UIApplication的生命周期通知底下的监听者,这些监听者必须遵循AppLifecycleListener协议,如果需要监听者要能扩展新的方法。
class AppLifecycleMediator: NSObject {
    private let listeners: [AppLifecycleListener]

    init(listeners: [AppLifecycleListener]) {
        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 = VideoListener()
        let listener2 = SocketListener()
        return AppLifecycleMediator(listeners: [listener1, listener2])
    }
}

2.3 这样就可以了。具体的请细看这篇文章 Massive App Delegate。我只是一个代码的搬运工。
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 194,088评论 5 459
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 81,715评论 2 371
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 141,361评论 0 319
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,099评论 1 263
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 60,987评论 4 355
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,063评论 1 272
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,486评论 3 381
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,175评论 0 253
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,440评论 1 290
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,518评论 2 309
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,305评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,190评论 3 312
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,550评论 3 298
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 28,880评论 0 17
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,152评论 1 250
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,451评论 2 341
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,637评论 2 335

推荐阅读更多精彩内容

  • Swift1> Swift和OC的区别1.1> Swift没有地址/指针的概念1.2> 泛型1.3> 类型严谨 对...
    cosWriter阅读 11,065评论 1 32
  • 关于组件化 网上组件化的文章很多。很多文章一提到组件化,就会说解耦,一说到解耦就会说路由或者runtime。好像组...
    朱大爷12138阅读 20,756评论 17 130
  • 1.属性readwrite,readonly,assign,retain,copy,nonatomic 各是什么作...
    曾令伟阅读 1,040评论 0 10
  • 模块化与解耦 简述 本文主要讲述了在iOS开发过程中,模块化工程架构的一种组织方式,本文主要讲述基于cocoapo...
    其实也没有阅读 433评论 0 4
  • 概述 在多数移动应用中任何时候都只能有一个应用程序处于活跃状态,如果其他应用此刻发生了一些用户感兴趣的那么通过通知...
    莫离_焱阅读 6,471评论 1 8