// 友盟统计
// JPush
// 分享相关
// 基础数据
// 数据库
// 等等...
无穷无尽的需求堆在Appdelegate中将会不忍直视.
1. 各组件分开引入
关于组件的拆分,就根据具体项目进行拆分,假如APP被拆分了AModule、BModule、CModule,那么,应该如何引入这些组件呢?你可能会想到APP的入口AppDelegate。在平时开发中,AppDelegate中往往初始化了好多组件,比如推送、统计等组件,这样就会导致AppDelegate的臃肿。
所以,我们可以增加一个ModuleManager ,专门用来初始化各组件。
首先增加一个 ModuleProtocol:
#import <Foundation/Foundation.h>
@import UIKit;
@import UserNotifications;
@protocol ModuleProtocol <UIApplicationDelegate, UNUserNotificationCenterDelegate>
@end
我们在ModuleManager
中hook住UIApplicationDelegate
和 UNUserNotificationCenterDelegate
中的方法,使相应的组件中实现了对应方法,在相应时机就会调用组建里的对应方法:
#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只需要实现协议ModuleProtocol
,然后实现AppDelegate
中对应的方法,在对应方法中初始化自身即可:
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
这样,各组件的开发者在自己的组件中初始化自己,其他人需要使用时只需要加入ModulesRegister.plist
文件中即可。