In order to study componentization, we mainly discuss mogujie routing + protocol pattern and middleware
We will discuss the first approach and implement a working demo with reference to Mogujie IOS componentization and discuss the pros and cons.
routing
Using MGJRouter singletons, through subscription or registration and publication or use. It’s definitely a little fuzzy, so let’s start coding.
Determine unique identifier
Through the MGJ: / / detail? Id =:id register with MGJ ://detail? Id =5, pass the parameter, first we find the similarity between the two urls, In the following code I use a simple algorithm + (NSString *)keyWithUrlStr:(NSString *)urlStr to get a unique identifier mgj_detail_id*, which can be registered and used through map
registerURLPattern:toHandler:
registeredopenURL:
The calling component
@interface MGJRouter : NSObject
// Comments can be made in one unified place
//mgj://detail? id=:id
+ (void)registerURLPattern:(NSString *)pattern
toHandler:(void(^)(NSDictionary *dic))block;
// Trigger the component's callback
//mgj://detail? id=5
+ (void)openURL:(NSString *)urlStr;
@end
@interface MGJRouter()
@property (nonatomic,strong) NSMutableDictionary * map;
@end
@implementation MGJRouter
- (instancetype)init {
if (self = [super init]) {
self.map = [NSMutableDictionary dictionary];
}
return self;
}
+ (MGJRouter *)shareManager {
static dispatch_once_t onceToken;
static MGJRouter * router = nil;
dispatch_once(&onceToken, ^{
if (router == nil) {
router = [[MGJRouter alloc] init]; }});return router;
}
// Comments can be made in one unified place
+ (void)registerURLPattern:(NSString *)pattern
toHandler:(void(^)(NSDictionary *dic))block {
NSString * key = [self keyWithUrlStr:pattern];
[self shareManager].map[key] = block;
}
// Trigger the component's callback
+ (void)openURL:(NSString *)urlStr {
NSString * key = [self keyWithUrlStr:urlStr];
NSLog(@"key = %@",key);
void(^block)(NSDictionary *dic) = [self shareManager].map[key];
if (block) {
NSMutableDictionary * param = nil;
NSURL * url = [NSURL URLWithString:urlStr];
NSString * query = url.query;
if (query.length) {
NSArray * items = [query componentsSeparatedByString:@"&"];
param = [NSMutableDictionary dictionary];
for (NSString * item in items) {
NSArray * littleItems = [item componentsSeparatedByString:@"="];
NSString * itemFirst = littleItems.firstObject;
NSString * itemSecond = littleItems.lastObject;
if(itemFirst && itemSecond) { param[itemFirst] = itemSecond; } } } block(param); }}//mgj://detail? id=:id
// Protocol name MGJ
// host detail
// query id=:id
/ / the MGJ: / / detail? Id = : id and MGJ: / / detail? Id =5 is converted to the same unique key
+ (NSString *)keyWithUrlStr:(NSString *)urlStr {
NSURL * url = [NSURL URLWithString:urlStr];
NSString * query = url.query;
NSString * queryStr = @"";
if (query.length) {
NSArray * items = [query componentsSeparatedByString:@"&"];
for (NSString * item in items) {
NSString * itemFirst = [item componentsSeparatedByString:@"="].firstObject;
queryStr = [queryStr stringByAppendingString:itemFirst];
queryStr = [queryStr stringByAppendingString:@"*"]; }}return [NSString stringWithFormat:@"% @ _ % @ _ % @",url.scheme,url.host,queryStr];
}
@end
Copy the code
The test component
// Register a component (usually unregistered at startup)
[MGJRouter registerURLPattern:@"mgj://detail? id=:id&name=:name" toHandler:^(NSDictionary *dic) {
NSString * oneId = dic[@"id"];
NSString * name = dic[@"name"];
if (oneId && name) {
// Create the component and get the value from the dictionary
DetailComposite * detail = [[DetailComposite alloc] init];
detail.oneId = oneId;
detail.name = name;
// Execute the component's methods[detail showComposite]; }}];// External calls execute a component
[MGJRouter openURL:@"mgj://detail? id=5&name=leeDev"];
// Print out: showComposite _ id = 5; name = leeDev
Copy the code
Summarizing routing Functions
The map is used to store the key -> component’s function block, which is called directly by passing parameters and keys through open and passing parameters.
Protocol (Protocol – Class)
Because we componentize in order not to expose our implementation classes, but we can expose some interfaces in order to reduce coupling.
Mogujie is managed through the ModuleManager protocol and class association in two main ways
@interface ModuleManager : NSObject
+ (void)registerClassName:(NSString *)className forProtocolName:(NSString *)protocolName;
+ (Class)classForProtocolName:(NSString *)protocolName;
@end
@interface ModuleManager()
@property (nonatomic,strong) NSMutableDictionary * map;
@end
@implementation ModuleManager
- (instancetype)init {
if (self = [super init]) {
self.map = [NSMutableDictionary dictionary];
}
return self;
}
+ (ModuleManager *)shareManager {
static dispatch_once_t onceToken;
static ModuleManager * router = nil;
dispatch_once(&onceToken, ^{
if (router == nil) {
router = [[ModuleManager alloc] init]; }});return router;
}
+ (void)registerClassName:(NSString *)className forProtocolName:(NSString *)protocolName {
[self shareManager].map[protocolName] = className;
}
+ (Class)classForProtocolName:(NSString *)protocolName {
NSString * className = [self shareManager].map[protocolName];
return NSClassFromString(className);
}
@end
Copy the code
Let’s say we want to get the number of shopping carts and we define a protocol
@protocol MGJCart <NSObject>
+ (NSInteger)orderCount;
@end
Copy the code
Implement the protocol in the implementation class
#import "MGjCart.h"
@interface MGJCartImp : NSObject<MGJCart>
@end
@implementation MGJCartImp
+ (NSInteger)orderCount {
// Process the logic and return the result
return 40;
}
@end
Copy the code
Registration and Use
// We just need to register the protocol
[ModuleManager registerClassName:@"MGJCartImp" forProtocolName:@"MGJCart"];
// From class, we just expose the MGJCart protocol
Class cla = [ModuleManager classForProtocolName:@"MGJCart"];
NSInteger orderCount = [(id <MGJCart>)cla orderCount];
NSLog(@"orderCount = %@",@(orderCount));
// Print orderCount = 40
Copy the code
The advantages and disadvantages
advantages
- Reduced coupling means that components depend only on urls, not on specific classes
disadvantages
- Passing object types such as image is troublesome, urls are not supported
- Callback blocks can also be cumbersome and can be called back from dictionaries, but they need to be well documented for the user to use them properly
- The use of protocol-classes is also cumbersome, generally the class instance is one
singleton
Because all the calls are+ method
.