iOS-模块解耦

最初在网上看到相关内容,是蘑菇街组件化相关讨论。(Limboy(文章1 文章2) 和 Casa (文章))。
但是我大家讨论的内容应该是如何解耦吧,而不是组件化本身,只不过解耦是组件化的前提而已。
我现在理解的有两种方案:

一、中间件+runtime

//Mediator.m
@implementation Mediator
+ (UIViewController *)BookDetailComponent_viewController:(NSString *)bookId {
 Class cls = NSClassFromString(@"BookDetailComponent");
 return [cls performSelector:NSSelectorFromString(@"detailViewController:") withObject:@{@"bookId":bookId}];
}
+ (UIViewController *)ReviewComponent_viewController:(NSString *)bookId type:(NSInteger)type {
 Class cls = NSClassFromString(@"ReviewComponent");
 return [cls performSelector:NSSelectorFromString(@"reviewViewController:") withObject:@{@"bookId":bookId, @"type": @(type)}];
}
@end

当然直接这样写,组件(模块)多了以后,这个中间件将会变的异常庞大,所以可以通过category方式分离组件接口代码。这里有个文章具体讲解了细节实现,增加了通过 target-action 简化写法。

二、URL+Block

中间件提供方法,可以将url和block进行绑定,各组件都要首先调用注册方法,把自己的功能(block)和对应的url注册到中间件中,才能让其他组件通过url调用。
一个简化的实现:

//Mediator.m 中间件
@implementation Mediator
typedef void (^componentBlock) (id param);
@property (nonatomic, storng) NSMutableDictionary *cache
- (void)registerURLPattern:(NSString *)urlPattern toHandler:(componentBlock)blk {
 [cache setObject:blk forKey:urlPattern];
}

- (void)openURL:(NSString *)url withParam:(id)param {
 componentBlock blk = [cache objectForKey:url];
 if (blk) blk(param);
}
@end
//BookDetailComponent 组件
#import "Mediator.h"
#import "WRBookDetailViewController.h"
+ (void)initComponent {
 [[Mediator sharedInstance] registerURLPattern:@"weread://bookDetail" toHandler:^(NSDictionary *param) {
 WRBookDetailViewController *detailVC = [[WRBookDetailViewController alloc] initWithBookId:param[@"bookId"]];
 [[UIApplication sharedApplication].keyWindow.rootViewController.navigationController pushViewController:detailVC animated:YES];
 }];
}
//WRReadingViewController.m 调用者
//ReadingViewController.m
#import "Mediator.h"

+ (void)gotoDetail:(NSString *)bookId {
 [[Mediator sharedInstance] openURL:@"weread://bookDetail" withParam:@{@"bookId": bookId}];
}

方案2最大的问题就是每个组件都需要初始化,内存里需要保存一份表,组件多了会有内存问题。

参考:iOS 组件化方案探索