業(yè)務(wù)背景
APP項(xiàng)目不斷迭代,業(yè)務(wù)不斷增加,項(xiàng)目工程越來(lái)越復(fù)雜。開(kāi)發(fā)團(tuán)隊(duì)不斷變大,各個(gè)人員有自己習(xí)慣的代碼風(fēng)格,代碼庫(kù),第三方等。為了保證業(yè)務(wù)不斷增長(zhǎng)擴(kuò)充,更加便捷管理代碼。提出組件化思想。不同模塊不同組分別 維護(hù)開(kāi)發(fā)。組件化思想核心:解耦合。
組件化優(yōu)勢(shì)
組件和組件之間沒(méi)有明確的約束,組件單獨(dú)開(kāi)發(fā)、單獨(dú)測(cè)試,不能揉入主項(xiàng)目中開(kāi)發(fā),測(cè)試也可以針對(duì)性的測(cè)試。
實(shí)現(xiàn)思路
簡(jiǎn)單來(lái)說(shuō)就是每個(gè)組件可以想象成一個(gè)單獨(dú)的APP,單獨(dú)的項(xiàng)目。各玩?zhèn)€的。但是不同模塊直接又存在著交互,數(shù)據(jù)交互,頁(yè)面交互,跳轉(zhuǎn)等等。想要跳轉(zhuǎn)又不能相互藕合,就需要一個(gè)“中間商”,中心路由,就是我們要研究的核心。我們主要解決的就是這個(gè)問(wèn)題。
項(xiàng)目管理實(shí)現(xiàn)
不同組件傳入不同Git地址,制作podspec支持pod導(dǎo)入。很簡(jiǎn)單不細(xì)說(shuō),網(wǎng)上很多資料。我們主要來(lái)看看組件間的通信。
實(shí)現(xiàn)方式
網(wǎng)上有很多種實(shí)現(xiàn)方法,總結(jié)大概一下三種:
1.url-block
2.protocol-class
3.target-action
一、url-block
概述:A組件使用URL將Block注冊(cè)給路由,路由以URL為KEY,將Block存儲(chǔ)起來(lái)。B組件通過(guò)URL調(diào)用路由的方法,找到對(duì)應(yīng)Block.完成對(duì)A的調(diào)用。
//
// Router.h
// XXOCDemo
//
// Created by admin on 2021/12/22.
//
#import <Foundation/Foundation.h>
NS_ASSUME_NONNULL_BEGIN
typedef void(^RouterBlock)(NSDictionary *dic);
@interface Router : NSObject
#pragma mark - URL
// A:aTestAction 參數(shù) @{@"text":...}
#pragma mark -
+ (instancetype)sharedInstance;
// 注冊(cè)
- (void)registerUrl:(NSString *)url block:(RouterBlock)block;
// 執(zhí)行
- (void)excuteBlockWithUrl:(NSString *)key params:(NSDictionary *)params;
@end
NS_ASSUME_NONNULL_END
//
// Router.m
// XXOCDemo
//
// Created by admin on 2021/12/22.
//
#import "Router.h"
@interface Router()
@property (strong, nonatomic) NSMutableDictionary *map;
@end
@implementation Router
+ (instancetype)sharedInstance {
static Router *_sharedSingleton = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
_sharedSingleton = [[super allocWithZone:NULL] init];
});
return _sharedSingleton;
}
// 防止外部調(diào)用alloc 或者 new
+ (instancetype)allocWithZone:(struct _NSZone *)zone {
return [Router sharedInstance];
}
// 防止外部調(diào)用copy
- (id)copyWithZone:(nullable NSZone *)zone {
return [Router sharedInstance];
}
// 防止外部調(diào)用mutableCopy
- (id)mutableCopyWithZone:(nullable NSZone *)zone {
return [Router sharedInstance];
}
// 注冊(cè)
- (void)registerUrl:(NSString *)url block:(RouterBlock)block{
if (!url || !block) return;
self.map[url] = block;
}
// 執(zhí)行
- (void)excuteBlockWithUrl:(NSString *)key params:(NSDictionary *)params {
if (!key) return;
RouterBlock block = self.map[key];
if (!block) return;
block(params);
}
@end
//
// AModule.h
// XXOCDemo
//
// Created by admin on 2021/12/22.
//
#import <UIKit/UIKit.h>
NS_ASSUME_NONNULL_BEGIN
@interface AModule : UIViewController
@end
NS_ASSUME_NONNULL_END
//
// AModule.m
// XXOCDemo
//
// Created by admin on 2021/12/22.
//
#import "AModule.h"
#import "Router.h"
@interface AModule ()
@end
@implementation AModule
- (void)viewDidLoad {
[super viewDidLoad];
// 注冊(cè)
[[Router sharedInstance] registerUrl:@"A:aTestAction" block:^(NSDictionary * _Nonnull dic) {
[self aTestAction:dic[@"text"]];
}];
}
- (void)aTestAction:(NSString *)text{
NSLog(text);
}
@end
//
// BModule.h
// XXOCDemo
//
// Created by admin on 2021/12/22.
//
#import <UIKit/UIKit.h>
NS_ASSUME_NONNULL_BEGIN
@interface BModule : UIViewController
@end
NS_ASSUME_NONNULL_END
// BModule.m
// XXOCDemo
//
// Created by admin on 2021/12/22.
#import "BModule.h"
#import "Router.h"
@interface BModule ()
@end
@implementation BModule
- (void)viewDidLoad {
[super viewDidLoad];
// B組件調(diào)用A組件
[[Router sharedInstance] excuteBlockWithUrl:@"A:aTestAction" params:@{@"text":@"文字"}];
}
@end
注冊(cè)所產(chǎn)生的內(nèi)存占用并不是負(fù)擔(dān),主要是大量的注冊(cè)可能會(huì)明顯拖慢啟動(dòng)速度。缺點(diǎn)顯而易見(jiàn): 調(diào)用的時(shí)候傳參不明確
// B組件調(diào)用A組件
[[Router sharedInstance] excuteBlockWithUrl:@"A:aTestAction" params:@{@"text":@"文字"}];
2.protocol-class
同樣也是需要存儲(chǔ),根據(jù)協(xié)議存儲(chǔ)類名,注冊(cè)
//
// Router1.h
// XXOCDemo
//
// Created by admin on 2021/12/22.
//
#import <Foundation/Foundation.h>
NS_ASSUME_NONNULL_BEGIN
//協(xié)議
@protocol AService <NSObject>
- (void)aTestAction:(NSString *)text;
@end
@interface Router1 : NSObject
+ (instancetype)sharedInstance;
- (void)registerService:(Protocol *)service class:(Class)cls;
- (id)getObject:(Protocol *)service;
@end
NS_ASSUME_NONNULL_END
//
// Router1.m
// XXOCDemo
//
// Created by admin on 2021/12/22.
//
#import "Router1.h"
@interface Router1()
@property (strong, nonatomic) NSMutableDictionary *map;
@end
@implementation Router1
+ (instancetype)sharedInstance {
static Router1 *_sharedSingleton = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
_sharedSingleton = [[super allocWithZone:NULL] init];
});
return _sharedSingleton;
}
// 防止外部調(diào)用alloc 或者 new
+ (instancetype)allocWithZone:(struct _NSZone *)zone {
return [Router1 sharedInstance];
}
// 防止外部調(diào)用copy
- (id)copyWithZone:(nullable NSZone *)zone {
return [Router1 sharedInstance];
}
// 防止外部調(diào)用mutableCopy
- (id)mutableCopyWithZone:(nullable NSZone *)zone {
return [Router1 sharedInstance];
}
- (void)registerService:(Protocol *)service class:(Class)cls {
if (!service || !cls) return;
self.map[NSStringFromProtocol(service)] = cls;
}
- (id)getObject:(Protocol *)service {
if (!service) return nil;
Class cls = self.map[NSStringFromProtocol(service)];
id obj = [cls new];
if ([obj conformsToProtocol:service]) {
return obj;
}
return nil;
}
@end
//
// AModule.h
// XXOCDemo
//
// Created by admin on 2021/12/22.
//
#import <UIKit/UIKit.h>
NS_ASSUME_NONNULL_BEGIN
@interface AModule : UIViewController
- (void)aTestAction:(NSString *)text;
@end
NS_ASSUME_NONNULL_END
//
// AModule.m
// XXOCDemo
//
// Created by admin on 2021/12/22.
//
#import "AModule.h"
#import "Router1.h"
@interface AModule ()
@end
@implementation AModule
- (void)viewDidLoad {
[super viewDidLoad];
// 注冊(cè)
[[Router1 sharedInstance] registerService:@protocol(AService) class:self.class];
}
- (void)aTestAction:(NSString *)text{
NSLog(@"%@", text);
}
@end
//
// BModule.h
// XXOCDemo
//
// Created by admin on 2021/12/22.
//
#import <UIKit/UIKit.h>
NS_ASSUME_NONNULL_BEGIN
@interface BModule : UIViewController
@end
NS_ASSUME_NONNULL_END
//
// BModule.m
// XXOCDemo
//
// Created by admin on 2021/12/22.
//
#import "BModule.h"
#import "Router1.h"
#import "AModule.h"
@interface BModule ()
@end
@implementation BModule
- (void)viewDidLoad {
[super viewDidLoad];
AModule *service = [[Router1 sharedInstance] getObject:@protocol(AService)];
[service aTestAction:@"文字"];
}
@end
3.target-action
通過(guò)performSelector 方法調(diào)用,無(wú)需注冊(cè)
//
// Router2.h
// XXOCDemo
//
// Created by admin on 2021/12/22.
//
#import <Foundation/Foundation.h>
NS_ASSUME_NONNULL_BEGIN
@interface Router2 : NSObject
+ (instancetype)sharedInstance;
/// 調(diào)用方法
/// @param target 類
/// @param action 方法
/// @param params 參數(shù)
- (id)performWithTarget:(NSString *)target action:(NSString *)action params:(NSDictionary *)params;
@end
NS_ASSUME_NONNULL_END
//
// Router2.m
// XXOCDemo
//
// Created by admin on 2021/12/22.
//
#import "Router2.h"
@implementation Router2
+ (instancetype)sharedInstance {
static Router2 *_sharedSingleton = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
_sharedSingleton = [[super allocWithZone:NULL] init];
});
return _sharedSingleton;
}
+ (instancetype)allocWithZone:(struct _NSZone *)zone {
return [Router2 sharedInstance];
}
- (id)copyWithZone:(nullable NSZone *)zone {
return [Router2 sharedInstance];
}
- (id)mutableCopyWithZone:(nullable NSZone *)zone {
return [Router2 sharedInstance];
}
- (id)performWithTarget:(NSString *)target action:(NSString *)action params:(NSDictionary *)params {
Class cls; id obj; SEL sel;
cls = NSClassFromString(target);
if (!cls){
return nil;
}
sel = NSSelectorFromString(action);
if (!sel){
return nil;
}
obj = [cls new];
if (![obj respondsToSelector:sel]) {
return nil;
}
return [obj performSelector:sel withObject:params];
}
@end
//
// AModule.h
// XXOCDemo
//
// Created by admin on 2021/12/22.
//
#import <UIKit/UIKit.h>
NS_ASSUME_NONNULL_BEGIN
@interface AModule : UIViewController
- (void)aTestAction:(NSString *)text;
@end
NS_ASSUME_NONNULL_END
//
// AModule.m
// XXOCDemo
//
// Created by admin on 2021/12/22.
//
#import "AModule.h"
@implementation AModule
- (void)viewDidLoad {
[super viewDidLoad];
}
- (void)aTestAction:(NSString *)text{
NSLog(@"%@", text);
}
@end
//
// BModule.h
// XXOCDemo
//
// Created by admin on 2021/12/22.
//
#import <UIKit/UIKit.h>
NS_ASSUME_NONNULL_BEGIN
@interface BModule : UIViewController
@end
NS_ASSUME_NONNULL_END
//
// BModule.m
// XXOCDemo
//
// Created by admin on 2021/12/22.
//
#import "BModule.h"
#import "Router2.h"
@interface BModule ()
@end
@implementation BModule
- (void)viewDidLoad {
[super viewDidLoad];
[[Router2 sharedInstance] performWithTarget:@"AModule" action:@"aTestAction:" params:@{@"text":@"文字"}];
}
@end
總結(jié)
以上就是所有方法實(shí)現(xiàn),可根據(jù)個(gè)人喜好選擇。用的最多的是URL-Block方式,簡(jiǎn)單注冊(cè)就好,不用寫(xiě)協(xié)議方法,方法調(diào)用統(tǒng)一入口,不會(huì)像protocol,需要寫(xiě)協(xié)議,調(diào)用方法散落各處。實(shí)際上也沒(méi)有太大差別。個(gè)人推薦protocol方式,需要寫(xiě)協(xié)議,同時(shí)參數(shù)看起來(lái)更加明確。
個(gè)人感悟,交流學(xué)習(xí),如有不準(zhǔn)確請(qǐng)指出!!!