iOS | 關(guān)于AppDelegate瘦身的想法與實(shí)踐

隨著開(kāi)發(fā)的迭代升級(jí)共苛,不斷增加新的功能和職責(zé),AppDelegate中的代碼量也不斷增長(zhǎng),致使Massive催首,而精通 OOP 的我們自然會(huì)想法子對(duì)其瘦身。


AppDelegate

什么是AppDelegate泄鹏?

  • AppDelegate 是應(yīng)用程序的根對(duì)象郎任,即唯一代理:
    a、其提供應(yīng)用程序生命周期事件的暴露备籽。
    b舶治、其確保應(yīng)用程序與系統(tǒng)以及其他應(yīng)用程序正確的交互。
    c车猬、其通常承擔(dān)很多職責(zé)霉猛,這使得很難進(jìn)行更改,擴(kuò)展和測(cè)試珠闰。
  • 作為連接應(yīng)用程序和系統(tǒng)的協(xié)調(diào)者惜浅,他應(yīng)該總是:
    a、單一職責(zé)
    b伏嗜、易于擴(kuò)展
    c坛悉、易于測(cè)試

組合模式

  • 組合模式依據(jù)樹(shù)形結(jié)構(gòu)來(lái)組合對(duì)象,用來(lái)表示部分以及整體層次承绸。
    a裸影、它隸屬于結(jié)構(gòu)型模式
    b、主要分??組裝類(lèi)與??服務(wù)類(lèi)
    c八酒、它近似于簡(jiǎn)易SOA
  • 其作用體現(xiàn)為
    a空民、服務(wù)易插拔
    b、無(wú)需額外改變 AppDelegate

實(shí)踐環(huán)節(jié)

  • 樹(shù)節(jié)點(diǎn)(根節(jié)點(diǎn)):組裝類(lèi)
#import <Foundation/Foundation.h>

NS_ASSUME_NONNULL_BEGIN

@interface AppDelegateFactory : NSObject

@property (readonly) NSMutableArray *services;

+ (instancetype)standardFactory;

@end

NS_ASSUME_NONNULL_END
#import "AppDelegateFactory.h"

@interface AppDelegateFactory ()

@property (nonatomic, strong) NSMutableArray *services;

@end

@implementation AppDelegateFactory

+ (instancetype)standardFactory {
    static AppDelegateFactory *insance = nil;
    static dispatch_once_t once;
    dispatch_once(&once, ^{
        insance = [AppDelegateFactory new];
    });
    return insance;
}

- (instancetype)init
{
    self = [super init];
    if (self) {
        makeDefault(self);
    }
    return self;
}

NS_INLINE void makeDefault(AppDelegateFactory *factory) {
    
    [factory registeService:@"ComponentLaunchService"];
//    [factory registeService:@"ComponentPushService"];
//    [factory registeService:@"ComponentBackgroundService"];
}

- (void)registeService:(NSString *)serviceClassString {
    
    Class targetClass = NSClassFromString(serviceClassString);
    NSObject *service = [[targetClass alloc] init];
    
    if (![self.services containsObject:service])
        [self.services addObject:service];
}


#pragma mark - Lazy load

/**
 生命流程中,我們有時(shí)候需要保持調(diào)用順序界轩,所以采用數(shù)組結(jié)構(gòu)
 
 */
- (NSMutableArray *)services {
    if (!_services) {
        _services = [NSMutableArray array];
    }
    return _services;
}

@end
  • 子節(jié)點(diǎn)(功能單元):服務(wù)類(lèi)
#import <UIKit/UIKit.h>

@interface ComponentLaunchService : NSObject <UIApplicationDelegate>

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

@end
@implementation ComponentLaunchService

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

    /// launch your application

    return YES;
}
  • 植入流程
#import "AppDelegate.h"
#import "AppDelegateFactory.h"

@implementation AppDelegate

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
    // Override point for customization after application launch.
    
    self.window = [[UIWindow alloc] initWithFrame:[UIScreen mainScreen].bounds];
    
    id<UIApplicationDelegate> service;
    for(service in [AppDelegateFactory standardFactory].services){
        ///若服務(wù)響應(yīng)
        if ([service respondsToSelector:_cmd]) { 
            [service application:application didFinishLaunchingWithOptions:launchOptions];
        }
    }
    
    [self.window makeKeyAndVisible];
    return YES;
}

- (void)applicationDidEnterBackground:(UIApplication *)application {
    
    id<UIApplicationDelegate> service;
    for(service in [AppDelegateFactory standardFactory].services){
        if ([service respondsToSelector:_cmd]){
            [service applicationDidEnterBackground:application];
        }
    }
    //程序進(jìn)入后臺(tái),通知服務(wù)器
}

- (void)applicationWillEnterForeground:(UIApplication *)application {
    
    id<UIApplicationDelegate> service;
    for(service in [AppDelegateFactory standardFactory].services){
        if ([service respondsToSelector:_cmd]){
            [service applicationWillEnterForeground:application];
        }
    }
    //程序從后臺(tái)進(jìn)入前臺(tái)
}

- (void)applicationDidReceiveMemoryWarning:(UIApplication *)application {
    
    id<UIApplicationDelegate> service;
    for(service in [AppDelegateFactory standardFactory].services){
        if ([service respondsToSelector:_cmd]){
            [service applicationDidReceiveMemoryWarning:application];
        }
    }
    //收到內(nèi)存警告時(shí)
}

///..省略以下生命周期回調(diào)方法
@end

中介者模式

  • 中介者模式提供一個(gè)中介類(lèi)画饥,該類(lèi)通常處理不同類(lèi)之間的通信。
    a浊猾、其隸屬于行為型模式
    b抖甘、支持松耦合
  • 作用體現(xiàn)為:
    a、使代碼易于維護(hù)
    a葫慎、降低多個(gè)對(duì)象和類(lèi)之間的通信復(fù)雜性

實(shí)踐環(huán)節(jié)

  • 定義UIApplication的生命周期監(jiān)聽(tīng)者
import UIKit

class AppLifecycleMediator: NSObject {
    private var 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(onAppDidFinishLaunching), name: UIApplication.didFinishLaunchingNotification, object: nil)
        NotificationCenter.default.addObserver(self, selector: #selector(onAppDidReceiveMemoryWarning), name: UIApplication.didReceiveMemoryWarningNotification, object: nil)
    }
    
    @objc private func onAppDidFinishLaunching() {
        listeners.forEach { $0.onAppDidFinishLaunching() }
    }
    
    @objc func onAppDidReceiveMemoryWarning() {
        listeners.forEach { $0.onAppDidReceiveMemoryWarning() }
    }
}
  • 定義監(jiān)聽(tīng)協(xié)議與實(shí)現(xiàn)者
import UIKit

protocol AppLifecycleListener {
    func onAppDidFinishLaunching()
    func onAppDidReceiveMemoryWarning()
}

extension AppLifecycleListener {
    func onAppDidFinishLaunching() {}
    func onAppDidReceiveMemoryWarning() {}
}

//MARK: - Listeners.. (舉個(gè)栗子)

class SocketListener: AppLifecycleListener {
    func onAppDidFinishLaunching() {
        print("[開(kāi)啟長(zhǎng)鏈接..]")
    }
}
  • 定義靜態(tài)方法衔彻,進(jìn)行初始化
extension AppLifecycleMediator {
    static func makeDefaultMediator() -> AppLifecycleMediator {
        let socketListener = SocketListener()
        return AppLifecycleMediator(listeners: [socketListener])
    }
}
  • 植入中介人
import UIKit

@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {

    var window: UIWindow?

    // point code
    let mediator = AppLifecycleMediator.makeDefaultMediator()

    ///省略以下內(nèi)容
}
優(yōu)點(diǎn)在于
  • 僅需要一次初始化
  • 中介類(lèi)自動(dòng)訂閱事件
  • 監(jiān)聽(tīng)者Listener易于增減、對(duì)AppDelegate侵入弱

其實(shí)我們對(duì)AppDelegate都是維系代碼可維護(hù)度偷办,職責(zé)的劃分艰额,保證不會(huì)在部分修改時(shí)牽一發(fā)而動(dòng)全身,這樣使得代碼更靈活與茁壯椒涯,可隨時(shí)插拔與復(fù)用柄沮。
以上設(shè)計(jì)方式亦適用于,復(fù)雜模塊職能劃分废岂,本文僅做簡(jiǎn)單介紹與思考~??

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末祖搓,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子湖苞,更是在濱河造成了極大的恐慌拯欧,老刑警劉巖,帶你破解...
    沈念sama閱讀 216,544評(píng)論 6 501
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件财骨,死亡現(xiàn)場(chǎng)離奇詭異镐作,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)蚓再,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,430評(píng)論 3 392
  • 文/潘曉璐 我一進(jìn)店門(mén)滑肉,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)包各,“玉大人摘仅,你說(shuō)我怎么就攤上這事∥食” “怎么了娃属?”我有些...
    開(kāi)封第一講書(shū)人閱讀 162,764評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)护姆。 經(jīng)常有香客問(wèn)我矾端,道長(zhǎng),這世上最難降的妖魔是什么卵皂? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 58,193評(píng)論 1 292
  • 正文 為了忘掉前任秩铆,我火速辦了婚禮,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘殴玛。我一直安慰自己捅膘,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,216評(píng)論 6 388
  • 文/花漫 我一把揭開(kāi)白布滚粟。 她就那樣靜靜地躺著寻仗,像睡著了一般。 火紅的嫁衣襯著肌膚如雪凡壤。 梳的紋絲不亂的頭發(fā)上署尤,一...
    開(kāi)封第一講書(shū)人閱讀 51,182評(píng)論 1 299
  • 那天,我揣著相機(jī)與錄音亚侠,去河邊找鬼曹体。 笑死,一個(gè)胖子當(dāng)著我的面吹牛硝烂,可吹牛的內(nèi)容都是我干的混坞。 我是一名探鬼主播,決...
    沈念sama閱讀 40,063評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼钢坦,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼究孕!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起爹凹,我...
    開(kāi)封第一講書(shū)人閱讀 38,917評(píng)論 0 274
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤厨诸,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后禾酱,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體微酬,經(jīng)...
    沈念sama閱讀 45,329評(píng)論 1 310
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,543評(píng)論 2 332
  • 正文 我和宋清朗相戀三年颤陶,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了颗管。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 39,722評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡滓走,死狀恐怖垦江,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情搅方,我是刑警寧澤比吭,帶...
    沈念sama閱讀 35,425評(píng)論 5 343
  • 正文 年R本政府宣布,位于F島的核電站姨涡,受9級(jí)特大地震影響衩藤,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜涛漂,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,019評(píng)論 3 326
  • 文/蒙蒙 一赏表、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦瓢剿、人聲如沸岁诉。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 31,671評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)涕癣。三九已至,卻和暖如春前标,著一層夾襖步出監(jiān)牢的瞬間坠韩,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 32,825評(píng)論 1 269
  • 我被黑心中介騙來(lái)泰國(guó)打工炼列, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留只搁,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 47,729評(píng)論 2 368
  • 正文 我出身青樓俭尖,卻偏偏與公主長(zhǎng)得像氢惋,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子稽犁,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,614評(píng)論 2 353

推薦閱讀更多精彩內(nèi)容

  • 專(zhuān)業(yè)考題類(lèi)型管理運(yùn)行工作負(fù)責(zé)人一般作業(yè)考題內(nèi)容選項(xiàng)A選項(xiàng)B選項(xiàng)C選項(xiàng)D選項(xiàng)E選項(xiàng)F正確答案 變電單選GYSZ本規(guī)程...
    小白兔去釣魚(yú)閱讀 8,985評(píng)論 0 13
  • javascript設(shè)計(jì)模式與開(kāi)發(fā)實(shí)踐 設(shè)計(jì)模式 每個(gè)設(shè)計(jì)模式我們需要從三點(diǎn)問(wèn)題入手: 定義 作用 用法與實(shí)現(xiàn) 單...
    穿牛仔褲的蚊子閱讀 4,057評(píng)論 0 13
  • Swift1> Swift和OC的區(qū)別1.1> Swift沒(méi)有地址/指針的概念1.2> 泛型1.3> 類(lèi)型嚴(yán)謹(jǐn) 對(duì)...
    cosWriter閱讀 11,097評(píng)論 1 32
  • 我也不記得是怎么關(guān)注到了剽悍一只貓焰望,覺(jué)得他特別牛逼,很想多了解他一點(diǎn)已亥,多向他學(xué)習(xí)熊赖,于是,我從他的第一篇文章開(kāi)始看虑椎。...
    常之韻閱讀 2,643評(píng)論 0 0
  • 中山橋 1522 兩側(cè)天橋 1525 法雨寺 1581 魁星閣 1605 三...
    jinlunzhai閱讀 524評(píng)論 0 0