// 友盟統(tǒng)計
// JPush
// 分享相關(guān)
// 基礎(chǔ)數(shù)據(jù)
// 數(shù)據(jù)庫
// 等等...
無窮無盡的需求堆在Appdelegate中將會不忍直視.
1. 各組件分開引入
關(guān)于組件的拆分,就根據(jù)具體項目進(jìn)行拆分,假如APP被拆分了AModule、BModule絮供、CModule,那么茶敏,應(yīng)該如何引入這些組件呢壤靶?你可能會想到APP的入口AppDelegate。在平時開發(fā)中惊搏,AppDelegate中往往初始化了好多組件贮乳,比如推送、統(tǒng)計等組件恬惯,這樣就會導(dǎo)致AppDelegate的臃腫向拆。
所以,我們可以增加一個ModuleManager 酪耳,專門用來初始化各組件亲铡。
首先增加一個 ModuleProtocol:
#import <Foundation/Foundation.h>
@import UIKit;
@import UserNotifications;
@protocol ModuleProtocol <UIApplicationDelegate, UNUserNotificationCenterDelegate>
@end
我們在ModuleManager
中hook住UIApplicationDelegate
和 UNUserNotificationCenterDelegate
中的方法,使相應(yīng)的組件中實現(xiàn)了對應(yīng)方法葡兑,在相應(yīng)時機(jī)就會調(diào)用組建里的對應(yīng)方法:
#import "ModuleManager.h"
#import "AppDelegate.h"
#import <objc/runtime.h>
#define ALL_MODULE [[ModuleManager sharedInstance] allModules]
#define SWIZZLE_METHOD(m) swizzleMethod(class, @selector(m),@selector(module_##m));
@interface ModuleManager ()
@property (nonatomic, strong) NSMutableArray<id<ModuleProtocol>> *modules;
@end
@implementation ModuleManager
+ (instancetype)sharedInstance {
static ModuleManager *instance = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
instance = [[ModuleManager alloc] init];
});
return instance;
}
- (void)loadModulesWithPlistFile:(NSString *)plistFile {
NSArray *modules = [NSArray arrayWithContentsOfFile:plistFile];
NSLog(@"%@", modules);
for (NSString *moduleName in modules) {
[self addModule:moduleName];
}
}
- (void)addModule:(NSString *)moduleName {
Class class = NSClassFromString(moduleName);
if (class_conformsToProtocol(class, @protocol(ModuleProtocol))) {
id<ModuleProtocol> module = [[class alloc] init];
[self.modules addObject:module];
}
}
- (NSMutableArray<id<ModuleProtocol>> *)modules {
if (!_modules) {
_modules = [[NSMutableArray alloc] init];
}
return _modules;
}
- (NSArray<id<ModuleProtocol>> *)allModules {
return self.modules;
}
@end
@implementation AppDelegate (Module)
+ (void)load
{
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
Class class = [self class];
SWIZZLE_METHOD(application:willFinishLaunchingWithOptions:);
SWIZZLE_METHOD(application:didFinishLaunchingWithOptions:);
......
});
}
static inline void swizzleMethod(Class class, SEL originalSelector, SEL swizzledSelector) {
// the method might not exist in the class, but in its superclass
Method originalMethod = class_getInstanceMethod(class, originalSelector);
Method swizzledMethod = class_getInstanceMethod(class, swizzledSelector);
// class_addMethod will fail if original method already exists
BOOL didAddMethod = class_addMethod(class, originalSelector, method_getImplementation(swizzledMethod), method_getTypeEncoding(swizzledMethod));
// the method doesn’t exist and we just added one
if (didAddMethod) {
class_replaceMethod(class, swizzledSelector, method_getImplementation(originalMethod), method_getTypeEncoding(originalMethod));
}
else {
method_exchangeImplementations(originalMethod, swizzledMethod);
}
}
- (BOOL)module_application:(UIApplication *)application willFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
BOOL result = [self module_application:application willFinishLaunchingWithOptions:launchOptions];
for (id<ModuleProtocol> module in ALL_MODULE) {
if ([module respondsToSelector:_cmd]) {
[module application:application willFinishLaunchingWithOptions:launchOptions];
}
}
return result;
}
- (BOOL)module_application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
BOOL result = [self module_application:application didFinishLaunchingWithOptions:launchOptions];
for (id<ModuleProtocol> module in ALL_MODULE) {
if ([module respondsToSelector:_cmd]) {
[module application:application didFinishLaunchingWithOptions:launchOptions];
}
}
return result;
}
......
@end
ModuleManager.h
:
#import <Foundation/Foundation.h>
#import "ModuleProtocol.h"
@interface ModuleManager : NSObject
+ (instancetype)sharedInstance;
- (void)loadModulesWithPlistFile:(NSString *)plistFile;
- (NSArray<id<ModuleProtocol>> *)allModules;
@end
之后我們通過一個 ModulesRegister.plist文件管理需要引入的組件:
如上圖奖蔓,假如我們要引入AModule、BModule讹堤、CModule吆鹤,那么這三個Module只需要實現(xiàn)協(xié)議ModuleProtocol
,然后實現(xiàn)AppDelegate
中對應(yīng)的方法洲守,在對應(yīng)方法中初始化自身即可:
AModule.h
:
#import <Foundation/Foundation.h>
#import "ModuleProtocol.h"
@interface AModule : NSObject<ModuleProtocol>
@end
AModule.m
:
#import "AModule.h"
@implementation AModule
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions{
//初始化AModule
return YES;
}
@end
之后在AppDelegate
的load
方法中通過ModulesRegister.plist
引入各組件即可:
@implementation AppDelegate
+ (void)load {
//load modules
NSString* plistPath = [[NSBundle mainBundle] pathForResource:@"ModulesRegister" ofType:@"plist"];
[[ModuleManager sharedInstance] loadModulesWithPlistFile:plistPath];
}
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
......
}
@end
這樣疑务,各組件的開發(fā)者在自己的組件中初始化自己沾凄,其他人需要使用時只需要加入ModulesRegister.plist
文件中即可。