iOS 组件化开发

iOS  组件化开发
在一个APP开发过程中,如果项目较小且团队人数较少,使用最基本的MVC、MVVM开发就已经足够了,因为维护成本比较低。 但是当一个项目开发团队人数较多时,因为每个人都会负责相应组件的开发,常规开发模式耦合会越来越严重,而且导致大量代码冲突,会使后期维护和升级过程中代码“牵一发而动全身”,额外带来很大的工作量,并且会导致一些潜在的BUG。在这时,组件化开发就派上很大用场了,所谓的组件化开发,就是把APP根据业务拆分为各独立的组件,各个组件相互写作,组成完整的APP。

一、各组件的引入

关于组件的拆分,就根据具体项目进行拆分,假如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 { ...... }

- (NSMutableArray<id<ModuleProtocol>> *)modules { ...... }

- (void)addModule:(id<ModuleProtocol>) module { ...... }

- (void)loadModulesWithPlistFile:(NSString *)plistFile { ...... }

- (NSArray<id<ModuleProtocol>> *)allModules { ...... }

@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) { ...... }


- (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 didFinishLaunching