如何高效管理AppDelegate中的<UIApplicationDelegate>


導(dǎo)語:

在實際開發(fā)過程中,我們常常需要在AppDelegate中監(jiān)聽用戶對應(yīng)用的操作,并做出回應(yīng),隨著應(yīng)用的復(fù)雜化,AppDelegate中的代碼量將非常復(fù)雜,非常不宜管理,且容易發(fā)生時序性的bug。我們應(yīng)該如何有效的管理AppDelegate呢?

1. AppDelegate中我們最常做的事

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
   ...
    return YES;
}

沒錯,創(chuàng)建應(yīng)用時,我們一定會在didFinishLaunchingWithOptions方法中,創(chuàng)建rootViewController和UIWindow。但是,在AppDelegate中,我們能做的還有很多。

2. AppDelegate還能做什么?

- (void)applicationDidEnterBackground:(UIApplication *)application {
   //當視頻正在播放時,用戶通過home回到手機主界面,我們需要讓PlayerManager在此方法中暫停播放。
   //如果我們應(yīng)用有下載功能,需要在這里實現(xiàn)暫停下載的邏輯。
   //開屏廣告需要在這個方法中開啟計時,當用戶再次回到應(yīng)用中,通過計時判斷是否需要展示開屏廣告。
}

- (void)applicationDidBecomeActive:(UIApplication *)application {
   //應(yīng)用再次回到前端時,有時候會進行一些必要的狀態(tài)請求。
   //是否需要再次開啟視頻播放和下載?
   //拉取登錄用戶信息,檢查是否在其他地方登錄,有沒有修改密碼?
}

- (void)application:(UIApplication *)application didReceiveLocalNotification:(nonnull UILocalNotification *)notification {
     //推送來了,要不要在應(yīng)用圖標上加上數(shù)字呢?
}

- (void)applicationWillTerminate:(UIApplication *)application {
    //應(yīng)用即將關(guān)閉,保存下載進度
    //注銷三方庫的授權(quán)工作
    //需要手動清理一些狀態(tài)值
}

我們發(fā)現(xiàn),在AppDelegate中,我們會將所有Manager執(zhí)行方法的入口都堆積在一個地方。這對于代碼閱讀和管理,以及bug的修改檢查都是非常不方便的。那么我們?nèi)绾谓鉀Q這個問題呢?

3. 讓我看看你有什么能耐?

在理論的代碼結(jié)構(gòu)中,我們會將功能性代碼封裝成一個一個的模塊,這些模塊是脫離業(yè)務(wù)邏輯層的。比如說,我們現(xiàn)在有一個廣告模塊,里面實現(xiàn)的方法有請求廣告,緩存廣告,用戶點擊上報等功能。這些都是脫離于業(yè)務(wù)層的,我們在任何頁面添加廣告功能,都是需要實現(xiàn)這些方法的。而廣告模塊也需要在AppDelegate中實現(xiàn)一些廣告請求和展示的邏輯。那么兩者之間就產(chǎn)生了關(guān)聯(lián)。

4. 解決問題的方法來了!

我們可以再創(chuàng)建一個AppEngine類,繼承UIApplicationDelegate,并在Manager中維護一個數(shù)組,將需要實現(xiàn)UIApplicationDelegate的類加入數(shù)組,統(tǒng)一管理。

Talk is cheap ,show me the code!

首先看看最終的實現(xiàn)結(jié)果,我們在AppDelegate中通過創(chuàng)建AppEngine類注冊需要實現(xiàn)UIApplicationDelegate的功能模塊(xxxManager),之后我們在AppEngine中實現(xiàn)注冊模塊調(diào)用UIApplicationDelegate的邏輯。

@interface AppDelegate ()

@end

@implementation AppDelegate

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {

    [AppEngine registerManager:[xxxManager new]];
    [AppEngine registerManager:[xxxManager new]];
    
    [[AppEngine shareEngine] application:application didFinishLaunchingWithOptions:launchOptions];
    
    return YES;
}

創(chuàng)建一個管理所有需要實現(xiàn)UIApplicationDelegate方法的功能模塊的AppEngine類。

@interface WQAppEngine : NSObject<UIApplicationDelegate>

+ (instancetype)shareEngine;;

/**********************************************************************/
#pragma mark - 模塊管理
/**********************************************************************/

+ (void)registerManager:(id<UIApplicationDelegate>)manager;
+ (void)unregisterManager:(id<UIApplicationDelegate>)manager;
+ (id)managerWithClass:(Class)aClass;

@end

我們以didFinishLaunchingWithOptions方法為例,如果某個功能模塊

static AppEngine *appEngine = nil;
+ (instancetype)shareEngine{
    static dispatch_once_t t;
    dispatch_once(&t, ^{
        appEngine = [[WQAppEngine alloc] init];
    });
    return appEngine;
}

/**********************************************************************/
#pragma mark - 模塊管理
/**********************************************************************/

+ (void)registerManager:(id<UIApplicationDelegate>)manager {
    ...
}

+ (void)unregisterManager:(id<UIApplicationDelegate>)manager {
    ...
}

+ (id)managerWithClass:(Class)aClass {
    for (id<UIApplicationDelegate> manager in engine.managerArray) {
        if ([manager isKindOfClass:aClass]) {
            return manager;
        }
    }
    return nil;
}


/**********************************************************************/
#pragma mark - UIApplicationDelegate
/**********************************************************************/

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(nullable NSDictionary *)launchOptions {
    DDLogDebug(@"%s", __FUNCTION__);

    __block BOOL flag = NO;
    [self.managerArray enumerateObjectsUsingBlock:^(id  _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
        if ([obj respondsToSelector:@selector(application:didFinishLaunchingWithOptions:)]) {
            BOOL tempFlag = [obj application:application didFinishLaunchingWithOptions:launchOptions];
            if (!flag) {
                flag = tempFlag;
            }
        }
    }];
    return flag;
}

5. 我們?yōu)槭裁床恢苯幼尭鱾€模塊Manager繼承UIApplicationDelegate?

首先,這么做是可以的。但從封裝的角度來講,各個功能模塊因為是脫離邏輯層,我們可以將模塊封裝成庫,在任何應(yīng)用中引入使用的。如果我們將這個庫引入新開發(fā)App中,但是這個APP現(xiàn)在不需要廣告功能,我們只需要在AppDelegatedidFinishLaunchingWithOptions方法中,將注冊廣告Manager的方法注銷掉即可。

我們是如何實現(xiàn)上面一段說的統(tǒng)一管理的?
我們拿廣告模塊來舉例說明,在AppEngine中我們已經(jīng)實現(xiàn)了方法:

+ (id)managerWithClass:(Class)aClass {
    for (id<UIApplicationDelegate> manager in engine.managerArray) {
        if ([manager isKindOfClass:aClass]) {
            return manager;
        }
    }
    return nil;
}

隨后創(chuàng)建一個AppEngine的廣告Manager類別,實現(xiàn)一個創(chuàng)建單例的方法:

@implementation AppEngine (Advert)

+ (nullable AdvertManager *)advertManager {
    return [self managerWithClass:[AdvertManager class]];
}
@end

因為AppEngine是單例,所以這里我們也只會創(chuàng)建一次AdvertManager。這樣一來,如果我們沒有在AppDelegatedidFinishLaunchingWithOptions方法中,注冊AdvertManager,那么AdvertManager其實就是為空。

@interface AppDelegate ()

@end

@implementation AppDelegate

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {

    //[AppEngine registerManager:[AdvertManager new]];
    [AppEngine registerManager:[xxxManager new]];
    
    [[AppEngine shareEngine] application:application didFinishLaunchingWithOptions:launchOptions];
    
    return YES;
}
最后編輯于
?著作權(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)容