你好,歡迎來到IOS教程網

 Ios教程網 >> IOS編程開發 >> IOS開發綜合 >> iOS項目組件化解耦

iOS項目組件化解耦

編輯:IOS開發綜合

最近給公司的一個iOS項目進行組件化解耦。本身項目早期開發就不是很規范,而且剛剛開始熟悉這個項目對業務方面也不是很熟悉所以並沒有對所有的模塊進行組件化。而且組件化解耦後還存在一些問題在文章中都會寫出來。
原理和蘑菇街 App 的組件化之路類似,但是也有一些不同並沒有加入「組件A」要調用「組件B」的某個方法這種業務場景。所有組件化的模塊都是「組件A」要調用「組件B」的這種情況。「組件A」與「組件B」之間是透明的。


為何要對項目組件化

對每個模塊間相互調用解耦統一wap與本地調用

首先說一下組件化帶來的最大好處就是給每個模塊間解耦。之前模塊間調用不得不相互引用,這就導致了各個模塊間相互依賴。想象一種場景:A,B,C,D是四個VC,四個VC之間是這樣的關系,A與B相互跳轉、B與C相互跳轉、D與A,B相互跳轉。它們之間的關系如下圖:

\

而組件化在項目中引入了Mediator對象與Action對象,引入這兩個對象後,A,B,C,D之間的關系如下圖:

<喎?/kf/ware/vc/" target="_blank" class="keylink">vcD4NCjxwPjxjb2RlPjxjb2RlPjxjb2RlPjxjb2RlPjxjb2RlPtXi0fm94bm5vs263Mfls/7By7b4x9Kyu7nctuDJ2bj21+m8/r3hubm2vMrH1eK49tH519Oho8/Cw+a74cu1w/c8Y29kZT5NZWRpYXRvcrbUz/PT6zxjb2RlPkFjdGlvbrbUz/O1xMq1z9ahozwvY29kZT48L2NvZGU+PC9jb2RlPjwvY29kZT48L2NvZGU+PC9jb2RlPjwvY29kZT48L3A+DQo8aHIgLz4NCjxwPjxjb2RlPjxjb2RlPjxjb2RlPjxjb2RlPjxjb2RlPjxjb2RlPjxjb2RlPrbU09rSu7j2PGNvZGU+QXBwwLTLtbHYsru/ycPitcS74dPQPGNvZGU+d2Fw0rPD5rX308M8Y29kZT5OYXRpdmW1xLmmxNyho82ouf08Y29kZT5VUkzXorLhyrXP1tfpvP67r7e9sLi/ydLUyrXP1s2s0ru49jxjb2RlPlVSTLy0v8nS1NTasb612LX308PX6bz+0rK/ydLU1No8Y29kZT53YXDSs8PmtffTw9fpvP6ho9Xi0fnUrbG+0qrU2sG9tKbNrMqxtKbA7bXEwt+8rc2z0ru3xdTawcs8Y29kZT5NZWRpYXRvcrbUz/PW0LSmwO2hozxiciAvPg0KtbHIu9Xi0fnX9tPQ0ru49sixteO+zcrHyOe5+zxjb2RlPndhcNKzw+a199PD0+uxvrXYtffTw82s0ru49sSjv+nQ6NKq1/ayu82stcS0psDtyrHO3reox/i31srH1NrExMDvtffTw7XEo6zS8s6qtrzKx82ouf3Su9H5tcQ8Y29kZT5VUkzAtLX308O1xKGjxL/HsNTaztLTxbuvtcTP7sS/1tCyosO709DV4tH5tcTQ6MfzoaPL+dLUtbHHsLXEt72wuMrHv8nQ0LXEoaPI57n71ea1xNKqx/i31rXEu7C/ydLUzai5/bSrtd2yu82stcSyzsr9wLTIt7aoyse008TEwO+3osbwtcS199PDoaM8L2NvZGU+PC9jb2RlPjwvY29kZT48L2NvZGU+PC9jb2RlPjwvY29kZT48L2NvZGU+PC9jb2RlPjwvY29kZT48L2NvZGU+PC9jb2RlPjwvY29kZT48L2NvZGU+PC9jb2RlPjwvY29kZT48L2NvZGU+PC9wPg0KPGhyIC8+DQo8aDIgaWQ9"組件化方案的實現">組件化方案的實現

通過程序啟動時注冊URL來實現組件化,URL注冊用通過JLRoutes實現的。
具體使用如下:


- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {

    JLRoutes *routes = [JLRoutes routesForScheme:scheme_url];

    [routes addRoute: LSYKey1 handler:^BOOL(NSDictionary * _Nonnull parameters) {
        //要處理的邏輯
        return YES; //判斷返回值來決定是否執行該處代碼
    }];
}

在上面的代碼中scheme_url是app自定義的協議,LSYKey1是URL的路徑,parameters是URL的參數。通過程序啟動初始化JLRoutes對象,並注冊不同的URL,當嘗試打開scheme_url協議的URL時就會執行對應注冊路徑下block內的代碼。

-(BOOL)application:(UIApplication *)application openURL:(NSURL *)url sourceApplication:(NSString *)sourceApplication annotation:(id)annotation   //當程序嘗試打開URL或者處理完從其它應用返回時會調用該方法 (不同版本的系統需要實現的方法不同)
{   
    if ([url.scheme isEqualToString:scheme_url]) {
       return  [JLRoutes routeURL:url];
    }
    return YES;
}

如果嘗試打開scheme_url://LSYKey1?oid=123&amount=456這樣的url時就會執行上面代碼中注冊的block。通過parameters取得該url的參數。

    JLRoutes *routes = [JLRoutes routesForScheme:scheme_url];

    [routes addRoute: LSYKey1 handler:^BOOL(NSDictionary * _Nonnull parameters) {
        NSInteger oid = [parameters[@"oid"] integerValue]; //獲取url中oid參數
        NSInteger amount = [parameters[@"amount"] integerValue]; //獲取url中amount參數

        return YES; 
    }];

上面說明如何通過JLRoutes注冊URL的,具體組件化解耦是Mediator對象與Action對象配合JLRoutes來實現的。
首先我們需要有一個文件來統一管理本地模塊的Key值,這裡在ComponentKey.h文件中進行管理

ComponentKey.h

#import 

static NSString * const LSYKey1 = @"LSYKey1";

static NSString * const LSYKey2 = @"LSYKey2";

static NSString * const LSYKey3 = @"LSYKey3";

...

Mediator對象實現的方法如下:

Mediator.h

#import 

@interface Mediator : NSObject

/**
 JLRountes注冊的url
 */
+(void)componentRegister;

/**
 本地通過key打開模塊

 @param key 模塊key
 @param dic 傳遞的參數
 */
+(void)openComponentForKey:(NSString *)key parameter:(NSDictionary *)dic;

/**
 該方法通過運行時的機制讓Mediator對象與Action對象解耦並將消息轉發給Action對象執行

 @param targetName Action對象名
 @param actionName 方法名
 @param params     傳遞的參數
 */
+(void)performTarget:(NSString *)targetName action:(NSString *)actionName params:(NSDictionary *)params;
@end

Mediator.m

@implementation Mediator


+(void)componentRegister
{
    JLRoutes *routes = [JLRoutes routesForScheme:scheme_url];

    [routes addRoute: LSYKey1 handler:^BOOL(NSDictionary * _Nonnull parameters) {
        [self performTarget:@"Action" action:@"performActionA" params:parameters];
        return YES;
    }];

        [routes addRoute: LSYKey2 handler:^BOOL(NSDictionary * _Nonnull parameters) {
        [self performTarget:@"Action" action:@"performActionB" params:parameters];
        return YES;
    }];


}
+(void)openComponentForKey:(NSString *)key parameter:(NSDictionary *)dic
{
    //將本地調用傳入的Key與參數轉拼接成url最後通過JLRoutes處理
    if (!key.length) {
        return;
    }
    NSMutableString *urlString = [NSMutableString stringWithString:[NSString stringWithFormat:@"%@://%@",scheme_url,key]];
    [urlString appendString:@"?"];
    [dic enumerateKeysAndObjectsUsingBlock:^(id  _Nonnull key, id  _Nonnull obj, BOOL * _Nonnull stop) {
        [urlString appendString:[NSString stringWithFormat:@"%@=%@&",key,obj]];
    }];
    [urlString deleteCharactersInRange:NSMakeRange(urlString.length-1, 1)];
    NSURL *url = [NSURL URLWithString:[urlString copy]];
    [JLRoutes routeURL:url];
}

+(void)performTarget:(NSString *)targetName action:(NSString *)actionName params:(NSDictionary *)params
{
    NSString *targetClassString = [NSString stringWithFormat:@"%@", targetName];
    NSString *actionString = [NSString stringWithFormat:@"%@:", actionName];

    Class targetClass = NSClassFromString(targetClassString);
    id target = [[targetClass alloc] init];
    SEL action = NSSelectorFromString(actionString);

    if ([target respondsToSelector:action]) {
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Warc-performSelector-leaks"
         [target performSelector:action withObject:params];
#pragma clang diagnostic pop
    } else {
        // 這裡是處理無響應請求的地方

        }
    }
}
@end

Action對象是處理從Mediator對象轉發過來的消息。上面分別執行了performActionA與performActionB的方法。我們可以根據功能給這些方法分類,如果performActionA與performActionB的方法都是執行跳轉操作,那麼我們添加一個Action(Jump)的category專門來處理跳轉操作。將這兩個方法寫入category中。

#import "Action+Jump.h"

@implementation Action (Jump)
-(void)performActionA:(NSDictionary *)params
{
    //跳轉A界面
}
-(void)performActionB:(NSDictionary *)params
{
    //跳轉B界面
}
@end

此時我們想要在本地調用LSYKey1模塊並要傳入oid與amount這兩個參數只要執行下面代碼即可:

[Mediator openComponentForKey:LSYKey1 parameter:@{@"oid":@123,@"amount":@"456"}];

遠程調用直接返回:

    [JLRoutes routeURL:url];

因為我們在程序啟動已經注冊了所有的url:

    [Mediator componentRegister];

存在的問題

上面雖然實現了組件化但是還是存在一些問題需要後續改進

本地調用與遠程調用混在一起無法區別開無法實現「組件A」要調用「組件B」的某個方法這種業務場景組件過多有可能影響程序啟動速度
  1. 上一頁:
  2. 下一頁:
蘋果刷機越獄教程| IOS教程問題解答| IOS技巧綜合| IOS7技巧| IOS8教程
Copyright © Ios教程網 All Rights Reserved