组件化-创建业务类私有库

2018年11月1日

一.工具类私有库,一般都是给大家一起使用的,基本都是底层的,大家都可以依赖它,他不依赖与任何组件。「所以最好先创建基础库,在创建业务库」

业务类私有库,如宣教库 HuHealtheducationKit(A库),培训库HuTrainKit(B库)。

A库里需要B库的页面, A库就需要dependenceB库;B库如何也需要A库的页面,B库就需要dependenceA库的页面; 这样就会出现循环引用无法同时做出A库和B库,于是我们可以引入秘书机制,引入宣教服务库HuHealtheducationCategoryKit(a库),和培训服务库HuTrainCategoryKit(b库)

这样A库如果需要B库的内容,A库依赖服务库b库;B库如果需要A库的功能,B库依赖a库就可以,这样就不会相互引用了。可以正常做库了

1.目前项目依赖的是CTMediator实现 https://github.com/casatwy/CTMediator

如果获取对象无返回值,或者返回是对象类型 真正跳转代码

[target performSelector:action withObject:params];

关键代码如下:

- (id)performTarget:(NSString *)targetName action:(NSString *)actionName params:(NSDictionary *)params shouldCacheTarget:(BOOL)shouldCacheTarget
{
    
    NSString *targetClassString = [NSString stringWithFormat:@"Target_%@", targetName];
    NSString *actionString = [NSString stringWithFormat:@"Action_%@:", actionName];
    Class targetClass;
    
    NSObject *target = self.cachedTarget[targetClassString];
    if (target == nil) {
        targetClass = NSClassFromString(targetClassString);
        target = [[targetClass alloc] init];
    }
    
    SEL action = NSSelectorFromString(actionString);
    
    if (target == nil) {
        // 这里是处理无响应请求的地方之一,这个demo做得比较简单,如果没有可以响应的target,就直接return了。实际开发过程中是可以事先给一个固定的target专门用于在这个时候顶上,然后处理这种请求的
        return nil;
    }
    
    if (shouldCacheTarget) {
        self.cachedTarget[targetClassString] = target;
    }
    if ([target respondsToSelector:action]) {
        return [self safePerformAction:action target:target params:params];
    } 
}
#pragma mark - private methods
- (id)safePerformAction:(SEL)action target:(NSObject *)target params:(NSDictionary *)params
{
    NSMethodSignature* methodSig = [target methodSignatureForSelector:action];
    if(methodSig == nil) {
        return nil;
    }
    const char* retType = [methodSig methodReturnType];
    if (strcmp(retType, @encode(void)) == 0) {
        NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:methodSig];
        [invocation setArgument:&params atIndex:2];
        [invocation setSelector:action];
        [invocation setTarget:target];
        [invocation invoke];
        return nil;
    }
    if (strcmp(retType, @encode(NSInteger)) == 0) {
        NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:methodSig];
        [invocation setArgument:&params atIndex:2];
        [invocation setSelector:action];
        [invocation setTarget:target];
        [invocation invoke];
        NSInteger result = 0;
        [invocation getReturnValue:&result];
        return @(result);
    }
    if (strcmp(retType, @encode(BOOL)) == 0) {
        NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:methodSig];
        [invocation setArgument:&params atIndex:2];
        [invocation setSelector:action];
        [invocation setTarget:target];
        [invocation invoke];
        BOOL result = 0;
        [invocation getReturnValue:&result];
        return @(result);
    }
    if (strcmp(retType, @encode(CGFloat)) == 0) {
        NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:methodSig];
        [invocation setArgument:&params atIndex:2];
        [invocation setSelector:action];
        [invocation setTarget:target];
        [invocation invoke];
        CGFloat result = 0;
        [invocation getReturnValue:&result];
        return @(result);
    }
    if (strcmp(retType, @encode(NSUInteger)) == 0) {
        NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:methodSig];
        [invocation setArgument:&params atIndex:2];
        [invocation setSelector:action];
        [invocation setTarget:target];
        [invocation invoke];
        NSUInteger result = 0;
        [invocation getReturnValue:&result];
        return @(result);
    }
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Warc-performSelector-leaks"
    return [target performSelector:action withObject:params];
#pragma clang diagnostic pop
}

#pragma mark - getters and setters
- (NSMutableDictionary *)cachedTarget
{
    if (_cachedTarget == nil) {
        _cachedTarget = [[NSMutableDictionary alloc] init];
    }
    return _cachedTarget;
}

二.具体实现创建宣教库A库,宣教服务a库, 培训库B库,培训服务库b库

1.创建HuHealtheducationKit库 参考:组件化-创建工具类私有库

第一步主要是设置podspec同那个文件

Pod::Spec.new do |s|
  s.name             = 'HuHealtheducationKit'
  s.version          = '1.0.5'
  s.summary          = 'A short description of HuHealtheducationKit.'
  s.description      = <<-DESC
TODO: Add long description of the pod here.
                       DESC
  s.homepage         = 'git@gitlab.317hu.com:HuModularizationLibrary/HuHealtheducationKit'
  # s.screenshots     = 'www.example.com/screenshots_1', 'www.example.com/screenshots_2'
  s.license          = { :type => 'MIT', :file => 'LICENSE' }
  s.author           = { 'wangyu204' => 'wangyu@317hu.com' }
  s.source           = { :git => 'git@gitlab.317hu.com:HuModularizationLibrary/HuHealtheducationKit.git', :tag => s.version.to_s }
  # s.social_media_url = 'https://twitter.com/<TWITTER_USERNAME>'
  s.ios.deployment_target = '8.0'
  #1. 文件所在的路径
  s.source_files = 'HuHealtheducationKit/Classes/*'
  #2. 需要公开出来的头文件,这样使用方就不需要引入多个头文件,直接引入这个头文件了
  s.public_header_files = 'HuHealtheducationKit/Classes/*.h'
  #3.预加载头文件,类似于主工程的pch文件,库里面代码就不需要在引入一般如下头文件,可能有先后顺序,一般把基础库写在最前面。
  s.prefix_header_contents = '#import <HuConfigsKit/HuConfigsHeader.h>','#import <MJExtension/MJExtension.h>','#import <HuCommonUIKit/HuCommonUIHeader.h>','#import <HuUtilsKit/HuUtilsHeader.h>','#import <HuCategoryKit/HuCategoryHead.h>','#import <HuMainProjectCategoryKit/CTMediator+HuMainProjectCategory.h>','#import <MJRefresh/MJRefresh.h>','#import <HuNetKit/HuNetHeader.h>','#import <IQKeyboardManager/IQKeyboardManager.h>','#import <SDWebImage/UIImageView+WebCache.h>','#import <Masonry/Masonry.h>'
  #4.实现页面分层功能
  s.subspec 'HuHealtheducation' do |ss|
      #4.0注意没有如下预计,因为HuHealtheducation目录下只有m文件夹,没有代码
      #ss.source_files =
      ss.subspec 'Models' do |sss|
          sss.source_files = 'HuHealtheducationKit/Classes/HuHealtheducation/Models/*'
      end
      ss.subspec 'Utils' do |sss|
          #4.1 需要有依赖 因为Utils文件用到了Models目录下面的类,(注意 Models就不能依赖Utils,不然就循环引用了)
          sss.dependency 'HuHealtheducationKit/HuHealtheducation/Models'
          #4.1.1填写的是组件名+文件夹名,不是物理目录
          sss.source_files = 'HuHealtheducationKit/Classes/HuHealtheducation/Utils/*'
      end
      ss.subspec 'Views' do |sss|
          #4.1
          sss.dependency 'HuHealtheducationKit/HuHealtheducation/Models'
          sss.dependency 'HuHealtheducationKit/HuHealtheducation/Utils'
          sss.source_files = 'HuHealtheducationKit/Classes/HuHealtheducation/Views/*'
      end
      ss.subspec 'ViewControllers' do |sss|
          #4.1
          sss.dependency 'HuHealtheducationKit/HuHealtheducation/Utils'
          sss.dependency 'HuHealtheducationKit/HuHealtheducation/Views'
          sss.dependency 'HuHealtheducationKit/HuHealtheducation/WBView'
          sss.source_files = 'HuHealtheducationKit/Classes/HuHealtheducation/ViewControllers/*'
      end
      ss.subspec 'WBView' do |sss|
          sss.source_files = 'HuHealtheducationKit/Classes/HuHealtheducation/WBView/*'
      end
  end
  #5.资源文件放xib文件 和图片文件
  s.resource_bundles = {
      'HuHealtheducationKit' => ['HuHealtheducationKit/Assets/*']
  }
  #6.依赖库  第3点可能会用到的头文件都需要直接或间接引入该库
  s.dependency 'HuMainProjectCategoryKit'
  s.dependency 'HuUtilsKit'
  s.dependency 'HuCommonUIKit'
  s.dependency 'MJExtension', '~> 3.0.13'
  s.dependency 'HuNetKit'
  s.dependency 'IQKeyboardManager', '~> 5.0.3'
  s.dependency 'Masonry'
  s.dependency 'SDWebImage', '~> 3.8.0'
  s.dependency 'HuSocketKit'
  s.dependency 'HuCWStarRateViewKit'
end

对应目录结构如下显示:


image.png

1.1几点补充
a.第3点设置的预加载头文件 pod install后就会在如下目录创建pch文件


image.png

b.资源文件放在如下右边目录,pod install后 就会在左边出现(配置文件第5点设置的)
image.png

2.第二步,创建 Target_HuHealtheducationKit类将需要公共出去的类或对象在个类里实现(因为需要依赖ViewControllers,我们就放在ViewControllers目录里了)【这个类时真正实现提供者】
2.1命名规则参照CTMediator的关键代码 「注意最好按如下约定填写,不然很容易找不到该类,或该方法」
类名:Target_库名。
方法名:Action_类名

//  Target_HuHealtheducationKit.h
#import <Foundation/Foundation.h>
@interface Target_HuHealtheducationKit : NSObject
//获取宣教主页
- (id)Action_getHealtheducationController:(NSDictionary *)params;
@end

//  Target_HuHealtheducationKit.m
#import "Target_HuHealtheducationKit.h"
#import "MainViewController.h"
@implementation Target_HuHealtheducationKit
//获取宣教主页
- (id)Action_getHealtheducationController:(NSDictionary *)params{
    return [[MainViewController alloc] init];
}
@end

2.2补充 如果是简单的获取viewController 我们也可以用如下方法回去 用运行时命令实现不引入头文件

使用:

UIViewController *vc = [[HuControllerId HuControllerShare] getViewControllerWithConName:@“HuWorkerSatisfactionViewController" paramType:HuPushNoParam param:nil];
[nav pushViewController:vc animated:YES];

所以,如果是获取view之类的推荐 用添加一个Action_方法

3.第三步创建宣教服务库HuHealtheducationCategoryKit(a库) 「其实是CTMediator的扩展方法」
3.1同样最主要的也是podspec文件 (该库只有两个文件,只是提供一个秘书中转服务,所以不需要分层这种)

Pod::Spec.new do |s|
    s.name             = 'HuHealtheducationCategoryKit'
    s.version          = '1.0.1'
    s.summary          = 'A short description of HuHealtheducationCategoryKit.'
    
    
    s.description      = <<-DESC
    TODO: Add long description of the pod here.
    DESC
    
    s.homepage         = 'git@gitlab.317hu.com:HuModularizationLibrary/HuHealtheducationCategoryKit'
    # s.screenshots     = 'www.example.com/screenshots_1', 'www.example.com/screenshots_2'
    s.license          = { :type => 'MIT', :file => 'LICENSE' }
    s.author           = { 'wangyu204' => 'wangyu@317hu.com' }
    s.source           = { :git => 'git@gitlab.317hu.com:HuModularizationLibrary/HuHealtheducationCategoryKit.git', :tag => s.version.to_s }
    
    s.ios.deployment_target = '8.0'
    
    s.source_files = 'HuHealtheducationCategoryKit/Classes/**/*'
    s.prefix_header_contents = '#import <HuConfigsKit/HuConfigsHeader.h>'
    
    s.dependency 'CTMediator'
    s.dependency 'HuConfigsKit'
end

3.2命名规范
推荐 CTMediator+库名
eg: CTMediator+HuHealtheducationCategoryKit

//  CTMediator+HuHealtheducationCategoryKit.h
#import <Foundation/Foundation.h>
#import <CTMediator/CTMediator.h>
@interface CTMediator(HuHealtheducationCategoryKit)
//获取宣教主页
- (id)getHealtheducationController;
@end

//  CTMediator+HuHealtheducationCategoryKit.m
#import "CTMediator+HuHealtheducationCategoryKit.h"
@implementation CTMediator (HuHealtheducationCategoryKit)
//获取宣教
- (id)getHealtheducationController{
    return [self performTarget:HuHealtheducationKit action:@"getHealtheducationController" params:nil shouldCacheTarget:NO];
}
@end

4.具体使用
需要用到A库的MainViewController (主干或其他库)引入对应的秘书服务库即可

#import <HuHealtheducationCategoryKit/CTMediator+HuHealtheducationCategoryKit.h>

 UIViewController *MPVc= [[CTMediator sharedInstance] getHealtheducationController];

4.1补充 如果抽离较慢我们可以 主干代码当成一个大的业务库C, 在主干里面创建一个 Target_HuMainProjectKit类
在创建一个主干的秘书服务库 CTMediator+HuMainProjectCategoryKit
这样需要抽离的库先放主干,等主干抽离好了,在把对应的服务方法放到对应的库哪里即可
eg:先放在主干里面

#import "CTMediator+HuMainProjectCategoryKit.h"
//隐藏或者显示tabbar
- (void)isHidenTabBar:(BOOL)isHiden vc:(UIViewController *)vc{
    
    NSMutableDictionary *dic = [[NSMutableDictionary alloc] init];
    [dic setObject:@(isHiden) forKey:@"isHiden"];
    [dic setObject:vc forKey:@"vc"];
    
    [self performTarget: HuMainProjectKit action:@"isHidenTabBar" params:dic shouldCacheTarget:NO];
}

等抽离好了

- (void)isHidenTabBar:(BOOL)isHiden vc:(UIViewController *)vc{
    
    NSMutableDictionary *dic = [[NSMutableDictionary alloc] init];
    [dic setObject:@(isHiden) forKey:@"isHiden"];
    [dic setObject:vc forKey:@"vc"];
    
    [self performTarget:HuLoginAndRegisterKit action:@"isHidenTabBar" params:dic shouldCacheTarget:NO];
}

5.用同样的方法就可以抽离培训库 HuTrainKit(B库)和培训服务库 HuTrainCategoryKit(b库),就可以上传做库了。做好后,就主干集成这些库,删除报错的重复文件即可。

如果您发现本文对你有所帮助,如果您认为其他人也可能受益,请把它分享出去。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 158,736评论 4 362
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,167评论 1 291
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 108,442评论 0 243
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 43,902评论 0 204
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,302评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,573评论 1 216
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,847评论 2 312
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,562评论 0 197
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,260评论 1 241
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,531评论 2 245
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,021评论 1 258
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,367评论 2 253
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,016评论 3 235
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,068评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,827评论 0 194
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,610评论 2 274
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,514评论 2 269

推荐阅读更多精彩内容