iOSApp組件化詳解(從0到1實(shí)現(xiàn)一個(gè)完整的組件化項(xiàng)目)

何為組件化

一種能夠解決代碼耦合的技術(shù)。項(xiàng)目經(jīng)過組件化的拆分挪丢,不僅可以解決代碼耦合的問題登刺,還可以增強(qiáng)代碼的復(fù)用性,工程的易管理性爱葵,減少編譯時(shí)間等

1.組件化分層架構(gòu)圖

App組件化架構(gòu)分層.png

2.架構(gòu)分層詳解

1.Lib層

基礎(chǔ)模塊跟業(yè)務(wù)無關(guān)施戴,只定義接口和基本配置,子類可以重寫萌丈,便于擴(kuò)展

  • LibBase
    • LibBaseController
    • LibBaseNavController
    • ...
  • LibCommon基礎(chǔ)公共組件
  • LibFlexBox移動(dòng)端FlexBox布局

Widget層

  • 由Lib延伸而來赞哗,便于組件的擴(kuò)展和復(fù)用

2.Mediator層

  • 采用Bifrost框架,創(chuàng)建調(diào)度組件并定義交互協(xié)議辆雾,處理業(yè)務(wù)模塊之間的數(shù)據(jù)傳遞及邏輯交互處理
  • Module層必須依賴該庫(kù)

3.Module層

業(yè)務(wù)層肪笋,跟業(yè)務(wù)相關(guān)的一些組件,業(yè)務(wù)組件之間互不依賴,且依賴于ModuleCommon層

ModuleCommon

跟業(yè)務(wù)相關(guān)的公共組件部分涂乌,例如

  • CommonBaseController
  • CommonLodingController
  • CommonListController
  • 數(shù)據(jù)模型Models
  • Tools工具類
  • Macro常見宏等
  • QMUI常見配置/換膚配置
  • 第三方分享/登錄/支付配置

3.組件化要點(diǎn)羅列

  • 多Target分模塊開發(fā)艺栈,代碼解耦
  • 單獨(dú)編譯項(xiàng)目
  • 組件之間傳值,通過調(diào)度組件Biforst
  • 組件間訪問公共圖片資源湾盒,解決命名沖突
  • 文件夾分層:子組件subspec
  • pod 引入依賴方式
    • 引入本地依賴
    • 引入遠(yuǎn)程依賴
    • 引入指定分支
  • 組件命名方式
  • App路由管理
  • podspec使用及格式校驗(yàn)
  • 組件間依賴管理
  • coapods私有化倉(cāng)庫(kù)搭建

**

3.1多Target分模塊開發(fā)湿右,代碼解耦

workspace 依賴多個(gè)功能文件開發(fā)

# Uncomment the next line to define a global platform for your project
# platform :ios, '9.0'
def commonPods()
    #基礎(chǔ)宏定義,類別
    pod 'HKMacros', :git => 'https://gitee.com/Steven_Hu/HKMacros.git'
    # 組件化基類-引用本地依賴
    pod 'HKBaseModule', :path => './PrivateRepo/HKBaseModule/HKBaseModule.podspec'
    #pod 'HKBaseModule', :git => 'https://gitee.com/Steven_Hu/HKBaseModule.git'
end

def mediatorPods()
    #pod 'Bifrost', :path => '../'
end

  # Comment the next line if you don't want to use dynamic frameworks
  #use_frameworks!
  #workspace文件名
  workspace 'HKiOSTools.xcworkspace'
  #主工程路徑
  project 'HKiOSTools/HKiOSTools.xcodeproj'

target 'HKiOSTools' do
    project 'HKiOSTools/HKiOSTools.xcodeproj'
    commonPods()
  
    target "HKBaseModule_Example" do
        project 'PrivateRepo/HKBaseModule/Example/HKBaseModule.xcodeproj'
        commonPods()
    end

end

**

3.2單獨(dú)編譯項(xiàng)目

如何區(qū)分你編譯的是主工程項(xiàng)目還是子工程項(xiàng)目

  • 最簡(jiǎn)單的方式罚勾,通過項(xiàng)目名稱:ProjectName

[[[NSBundle mainBundle] infoDictionary] objectForKey:(NSString *)kCFBundleExecutableKey]

  • 判斷項(xiàng)目名稱是否和子項(xiàng)目名稱一致即可

3.3組件之間傳值Bifrost

image.png

注冊(cè)路由(ViewController)

+ (void)load {
    [Bifrost bindURL:kRouteHomePage
           toHandler:^id _Nullable(NSDictionary * _Nullable parameters) {
        return [HKHomeViewController new];
    }];
}

獲取路由(ViewController)

UIViewController * vc = [Bifrost handleURL:kRouteHomePage];
[self.navigationController pushViewController:vc animated:YES];

頁(yè)面?zhèn)髦?/h4>
  • 以type為例
//1.當(dāng)前頁(yè)面聲明一個(gè)type屬性
/// 驗(yàn)證類型
@property (nonatomic, assign) HKVerifyType  type ;
// 2.bindURL
[Bifrost bindURL:kRouteBindPhoneNumPage toHandler:^id _Nullable(NSDictionary * _Nullable parameters) {
  HKBindPhoneNumViewController *vc = [[self alloc] init];
  vc.type = [parameters[kRouteBindPhoneNumParamType] integerValue];
  return vc;
}];
// 3.傳值type
NSString *routeURL = BFStr(@"%@?%@=%@", kRouteBindPhoneNumPage, kRouteBindPhoneNumParamType, @(HKVerifyTypeForgetPassword));
UIViewController * vc = [Bifrost handleURL:routeURL]
[self.navigationController pushViewController:vc animated:YES];

頁(yè)面回調(diào)處理

//1.當(dāng)前頁(yè)面聲明一個(gè)type屬性和Block
/// 驗(yàn)證類型
@property (nonatomic, assign) HKVerifyType  type ;
/// 完成回調(diào)
@property (nonatomic, strong) BifrostRouteCompletion complete ;
// 2.bindURL
[Bifrost bindURL:kRouteBindPhoneNumPage toHandler:^id _Nullable(NSDictionary * _Nullable parameters) {
    HKBindPhoneNumViewController *vc = [[self alloc] init];
    vc.type = [parameters[kRouteBindPhoneNumParamType] integerValue];
    vc.complete = parameters[kBifrostRouteCompletion];
    return vc;
}];
// 3.點(diǎn)擊事件處理
/// 獲取驗(yàn)證
- (void)getVerifyCodeEvent
{
    [self.view endEditing:YES];
    BFComplete(@{kBifrostRouteCompletion:self.complete}, @(self.type));
}
// 4.傳值type
UIViewController *vc = [Bifrost handleURL:kRouteBindPhoneNumPage complexParams:@{kRouteBindPhoneNumParamType:@(HKVerifyTypeForgetPassword)} completion:^(id  _Nullable result) {
    HKVerifyType type = (YNVerifyType)result;
    [HKKeyWindow hk_showWithText:HKStr(@"你點(diǎn)擊的類型是:%@",type)];
}];
[self.navigationController pushViewController:vc animated:YES];

3.4組件間訪問公共圖片資源

主工程有一個(gè)a.png的圖片毅人,而pod庫(kù)里面也有一個(gè)a.png的圖片,此時(shí)就產(chǎn)生命名沖突了

思路:不同的組件都有自己獨(dú)立的bundle尖殃,組件內(nèi)部資源提供自身的Bundle來獲取丈莺,以避免資源重復(fù)

  • 本地資源如圖片等存放位置(Assets文件夾,否則無法訪問)
image.png
  • 指定Bundle名稱
# resource_bundles
s.resource_bundles = {
   'HKLibCommon' => ['HKLibCommon/**/*.{xib,jpg,gif,png,xcassets}']
  }
  • 解決命名沖突:resource_bundles
  • resource_bundles會(huì)自動(dòng)生成bundle把資源文件打包進(jìn)去

加載本地資源方法

工具類抽取
#import <Foundation/Foundation.h>
#import <UIKit/UIKit.h>

@interface ModuleBundle : NSObject

/*
 * 根據(jù)bundle的名稱獲取bundle
 */
+ (NSBundle *)bundleWithName:(NSString *)bundleName;

//獲取bundle 每次只要重寫這個(gè)方法就可以在指定的bundle中獲取對(duì)應(yīng)資源
+ (NSBundle *)bundle;

//根據(jù)xib文件名稱獲取xib文件
+ (__kindof UIView *)viewWithXibFileName:(NSString *)fileName;

//根據(jù)圖片名稱獲取圖片
+ (UIImage *)imageNamed:(NSString *)imageName;

//根據(jù)sb文件名稱獲取對(duì)應(yīng)sb文件
+ (UIStoryboard *)storyboardWithName:(NSString *)storyboardName;

//獲取nib文件
+ (UINib *)nibWithName:(NSString *)nibName;

@end
#import "ModuleBundle.h"

@implementation ModuleBundle

+ (NSBundle *)bundleWithName:(NSString *)bundleName {
    if(bundleName.length == 0) {
        return nil;
    }
    NSString *path = [[NSBundle mainBundle] pathForResource:bundleName ofType:@"bundle"];
    NSAssert([NSBundle bundleWithPath:path], @"not found bundle");
    return  [NSBundle bundleWithPath:path];
}

+ (NSBundle *)bundle {
//    NSAssert([NSBundle mainBundle], @"not found bundle");
    return [NSBundle mainBundle];
}

+ (UIView *)viewWithXibFileName:(NSString *)fileName {
    NSAssert([self viewWithXibFileName:fileName inBundle:[self.class bundle]], @"not found view");
    return [self viewWithXibFileName:fileName inBundle:[self.class bundle]];
}

+ (UIImage *)imageNamed:(NSString *)imageName {
    NSAssert([self imageNamed:imageName inBundle:[self.class bundle]], @"not found image");
    return [self imageNamed:imageName inBundle:[self.class bundle]];
}

+ (UIStoryboard *)storyboardWithName:(NSString *)storyboardName {
    NSAssert([self storyboardWithName:storyboardName inBundle:[self.class bundle]], @"not found storyboard");
    return [self storyboardWithName:storyboardName inBundle:[self.class bundle]];
}

+ (UINib *)nibWithName:(NSString *)nibName {
    NSAssert([self nibWithNibName:nibName inBundle:[self.class bundle]], @"not found nib");
    return [self nibWithNibName:nibName inBundle:[self.class bundle]];
}

#pragma mark - private
+ (UIImage *)imageNamed:(NSString *)imageName inBundle:(NSBundle *)bundle {
    if(imageName.length == 0 || !bundle) {
        return nil;
    }
    return [UIImage imageNamed:imageName inBundle:bundle compatibleWithTraitCollection:nil];
}

+ (UIImage *)imageNamed:(NSString *)imageName bundleName:(NSString *)bundleName {
    return [self imageNamed:imageName inBundle:[self bundleWithName:bundleName]];
}

+ (UIView *)viewWithXibFileName:(NSString *)fileName inBundle:(NSBundle *)bundle {
    if(fileName.length == 0 || !bundle) {
        return nil;
    }
    //如果沒有國(guó)際化送丰,則直接去相應(yīng)內(nèi)容下的文件
    UIView *xibView = [[bundle loadNibNamed:fileName owner:nil options:nil] lastObject];
    if(!xibView) {
        //文件國(guó)際化之后缔俄,所有的bundle的文件資源都在base的目錄下
        xibView = [[[NSBundle bundleWithPath:[bundle pathForResource:@"Base" ofType:@"lproj"]] loadNibNamed:fileName owner:nil options:nil] lastObject];
    }
    return xibView;
}

+ (UIView *)viewWithXibFileName:(NSString *)fileName bundleName:(NSString *)bundleName {
    return [self viewWithXibFileName:fileName inBundle:[self bundleWithName:bundleName]];
}

+ (UIStoryboard *)storyboardWithName:(NSString *)storyboardName inBundle:(NSBundle *)bundle {
    if(storyboardName.length == 0 || !bundle) {
        return nil;
    }
    return [UIStoryboard storyboardWithName:storyboardName bundle:bundle];
}

+ (UIStoryboard *)storyboardWithName:(NSString *)storyboardName bundleName:(NSString *)bundleName {
    return [self storyboardWithName:storyboardName inBundle:[self bundleWithName:bundleName]];
}

+ (UINib *)nibWithNibName:(NSString *)nibName inBundle:(NSBundle *)bundle {
    if(nibName.length == 0 || !bundle ) {
        return nil;
    }
    return [UINib nibWithNibName:nibName bundle:bundle];
}

@end
Bundle獲取

創(chuàng)建一個(gè)類CommonBundle繼承自ModuleBundle,并實(shí)現(xiàn)以下方法

#import "CommonBundle.h"
@implementation CommonBundle
+ (NSBundle *)bundle{
    //TODO:注意Bundle名字需跟模塊名稱一致器躏,否則會(huì)找不到path俐载,直接Crash
    return [self.class bundleWithName:@"HKLibCommon"];
}
@end
使用

替換系統(tǒng)加載圖片的方式:[UIImage imageNamed:@"navigationbar_background"]

[CommonBundle imageNamed:@"navigationbar_background"]
多個(gè)包
spec.resource_bundles = {
    'MapBox' => ['MapView/Map/Resources/*.png'],
    'OtherResources' => ['MapView/Map/OtherResources/*.png']
  }

3.5文件夾分層子組件subspec

我們?cè)诰帉憄odspec文件時(shí),sourcefiles只是告訴pods你需要哪些文件是這個(gè)項(xiàng)目中需要的登失,而沒有包括文件的層級(jí)結(jié)構(gòu)遏佣,那么就需要我們來實(shí)現(xiàn)這個(gè)層級(jí)結(jié)構(gòu):subspec


image.png

比如這里面的每一個(gè)文件夾,就是一個(gè)子pod揽浙,這樣的好處是條理清晰状婶,而且我們可以只用你需要的功能,在編寫podfile時(shí) 就可以這樣寫
pod 'HKModuleModels/User' 只使用其中的一個(gè)功能馅巷。

主podspec

主pod可以是一個(gè)頭文件膛虫,也可以具有一定的功能,我寫的組件sourcefiles只是一個(gè)import子組件的頭文件钓猬, sourcebundle是項(xiàng)目中需要的一些圖片


image.png

編寫subspec

  • 讓pods支持子subspec其實(shí)很簡(jiǎn)單走敌,只要搞清楚三件事
  1. 文件夾結(jié)構(gòu) subspec sourcefiles的路徑
  2. subspec 所依賴的系統(tǒng)庫(kù)
  3. subspec 所依賴的第三方,和其它subspec的路徑
image.png

3.6pod 引入依賴方式

引入本地依賴

pod 'ManageLocalCode', :path => '../ManageLocalCode'
pod 'BioAuthAPI', :path => '../BioAuthAPI'
pod 'HKTool', :path => '../'

遠(yuǎn)程私有庫(kù)依賴:

# 基礎(chǔ)宏定義byStevenHu
pod 'HKMacros', :git => 'https://gitee.com/Steven_Hu/HKMacros.git'

指定分支

# 支付代碼測(cè)試
  iap_pay:
    git:
      url:  https://gitee.com/Steven_Hu/iap_pay.git
      ref: master

常規(guī)依賴

pod "AFNetworking",  "~>0.2.0"

3.7 組件命名方式

組件性質(zhì) 建議名稱 示例
基礎(chǔ)組件拆分 項(xiàng)目前綴Lib組件名稱 HKLibBase:基類模塊
業(yè)務(wù)組件拆分 項(xiàng)目前綴Module組件名稱 HKModuleHome:首頁(yè)模塊
調(diào)度組件拆分 項(xiàng)目前綴Mediator組件名稱 HKMediatorDriver:司機(jī)端調(diào)度組件
Wdiget組件拆分 項(xiàng)目前綴Widget組件名稱 HKWidgetAddressPicker:地址選擇器組件
公共組件 項(xiàng)目前綴_組件名稱_Common HKLibCommon,HKModuleCommon

3.8 App端路由管理

格式

app內(nèi)鏈

舉例yunquedriver://home/homepage/detail?name=steven&age=18
appscheme://moduleName/pageName/secondPageName?key1=value1&key2=value2
其中value中有中文等特殊字符時(shí)需要進(jìn)行urlEncode逗噩。

app外鏈外鏈

http://xxx
https://xxx

格式說明

  • appscheme分解
    • 項(xiàng)目名稱
      • yunque
    • 業(yè)務(wù)側(cè)
      • driver
      • user
  • moduleName
    • 業(yè)務(wù)模塊名稱
  • pageName
    • 頁(yè)面名稱
  • secondPage
    • 二級(jí)頁(yè)面

scheme

云雀司機(jī): yunquedriver
云雀用戶:yunqueuser

模塊名

lib:工具類掉丽,跟業(yè)務(wù)無關(guān)的

頁(yè)面

image.png

3.9 podspec使用及格式校驗(yàn)

注意事項(xiàng)

  • podspec版本號(hào)和git倉(cāng)庫(kù)代碼的tag版本必須一致,否則找不到
    • 比如:pod lib 默認(rèn)生成的是0.1.0异雁,我們根據(jù)業(yè)務(wù)需要改成0.0.1
  • 索引倉(cāng)庫(kù)和組件倉(cāng)庫(kù)關(guān)聯(lián)
    • cd到組件倉(cāng)庫(kù)目錄下
    • pod repo push #{本地關(guān)聯(lián)到遠(yuǎn)程倉(cāng)庫(kù)的名字} #{第三方私有庫(kù)的podspec文件} --verbose --allow-warnings 示例: pod repo push YNSpecs YNLibDemo.podspec --verbose --allow-warnings
  • 項(xiàng)目引入
# 遠(yuǎn)程私有倉(cāng)庫(kù)
source 'https://gitlab.com/xxxx/xxSpecs'

# 引入使用
pod 'xxLibNetwork'

3.10 組件間依賴管理

通過 git submodule add https://gitee.com/Steven_Hu/hk-module-components.git 添加submodule
會(huì)在git上添加一個(gè).gitmodules 文件捶障,可以查看各種依賴

[submodule "PrivateRepo/hk-lib-base"]
    path = PrivateRepo/hk-lib-base
    url = https://gitee.com/Steven_Hu/hk-lib-base.git
[submodule "PrivateRepo/hk-lib-common"]
    path = PrivateRepo/hk-lib-common
    url = https://gitee.com/Steven_Hu/hk-lib-common.git
[submodule "PrivateRepo/hk-lib-network"]
    path = PrivateRepo/hk-lib-network
    url = https://gitee.com/Steven_Hu/hk-lib-network.git
[submodule "PrivateRepo/hk-mediator"]
    path = PrivateRepo/hk-mediator
    url = https://gitee.com/Steven_Hu/hk-mediator.git
[submodule "PrivateRepo/hk-lib-keyboard"]
    path = PrivateRepo/hk-lib-keyboard
    url = https://gitee.com/Steven_Hu/hk-lib-keyboard.git
[submodule "PrivateRepo/hk-lib-avoid-app-crash"]
    path = PrivateRepo/hk-lib-avoid-app-crash
    url = https://gitee.com/Steven_Hu/hk-lib-avoid-app-crash.git
[submodule "PrivateRepo/hk-lib-load-picture"]
    path = PrivateRepo/hk-lib-load-picture
    url = https://gitee.com/Steven_Hu/hk-lib-load-picture.git
[submodule "PrivateRepo/hkmodule-models"]
    path = PrivateRepo/hkmodule-models
    url = https://gitee.com/Steven_Hu/hkmodule-models.git
[submodule "PrivateRepo/hk-module-uikit"]
    path = PrivateRepo/hk-module-uikit
    url = https://gitee.com/Steven_Hu/hk-module-uikit.git
[submodule "PrivateRepo/hk-module-components"]
    path = PrivateRepo/hk-module-components
    url = https://gitee.com/Steven_Hu/hk-module-components.git
[submodule "PrivateRepo/hk-module-main"]
    path = PrivateRepo/hk-module-main
    url = https://gitee.com/Steven_Hu/hk-module-main.git

最終結(jié)果如下圖所示,點(diǎn)擊跳轉(zhuǎn)新的submodule倉(cāng)庫(kù)地址


image.png

本地Clone方式

git clone https://gitee.com/Steven_Hu/hk-iostools.git
git submodule init && git submodule update

#下面這一句的效果和上面三條命令的效果是一樣的,多加了個(gè)參數(shù)  `--recursive`
git clone https://gitee.com/Steven_Hu/hk-iostools.git --recursive

常見問題

error: Server does not allow request for unadvertised object b22e0a5a2a8dce1d0454bdead70353bf45f33f81

Fetched in submodule path 'PrivateRepo/hk-module-main', but it did not contain b22e0a5a2a8dce1d0454bdead70353bf45f33f81. Direct fetching of that commit failed.

原因分析:

未拉取到該submodule的最新代碼

解決

git submodule foreach git checkout master
git submodule foreach git submodule update

3.11 coapods私有化倉(cāng)庫(kù)搭建

準(zhǔn)備工作

  • 安裝cocoapods
  • 準(zhǔn)備gitlab/gitee/getlab(下文統(tǒng)一稱為gitlab)等代碼倉(cāng)庫(kù)賬號(hào)

創(chuàng)建組建索引Spec倉(cāng)庫(kù)(用于存放組件庫(kù)的索引)

  • 在gitlab中創(chuàng)建XXSpecs倉(cāng)庫(kù)纲刀,初始化README.md(目的是倉(cāng)庫(kù)不為空)得到倉(cāng)庫(kù)地址
  • 在本地cocoapods中添加repo
pod repo add `specFileName(給spec倉(cāng)庫(kù)在本地的命名)` `spec(倉(cāng)庫(kù)的地址)`
實(shí)例:
pod repo add XXSpecs https://gitee.com/Steven_Hu/objective-c-specs

~/.cocoapods/repos目錄中可以看到創(chuàng)建的文件夾

image.png

  • 創(chuàng)建組件庫(kù)
    • pod lib create #{庫(kù)的名稱}
    • 實(shí)例 pod lib create XXLibDemo
  • 修改podspec文件
  • 將組件push到gitlab
  • 將索引倉(cāng)庫(kù)和組件倉(cāng)庫(kù)關(guān)聯(lián)
  • 項(xiàng)目引入
# 遠(yuǎn)程私有倉(cāng)庫(kù)
source 'https://gitlab.com/xxxx/xxSpecs'

# 引入使用
pod 'xxLibNetwork'

4.常見問題補(bǔ)充

4.1target has transitive dependencies that include statically linked binaries:

解決辦法

s.static_framework = true

4.2CocoaPods did not set the base configuration of your project because your project already...

使用CocoaPods安裝三方庫(kù)后有兩個(gè)警告,如下所示:


image.png

解決辦法:
將第三方庫(kù) 的 PROJECT → Info → Configurations 下Debug和Release下的.debug和.release選項(xiàng)替換為None,如下圖所示:


image.png

然后在pod install即可

4.3清除 CocoaPods 本地緩存

特殊情況下项炼,由于網(wǎng)絡(luò)或者別的原因,通過CocoaPods下載的文件可能會(huì)有問題。
這時(shí)候您可以刪除CocoaPods的緩存(~/Library/Caches/CocoaPods/Pods/Release目錄)锭部,再次導(dǎo)入即可暂论。

4.4pod spec lint編譯時(shí)報(bào)error: include of non-modular header inside framework module

解決辦法

pod lib lint --allow-warnings --use-libraries --verbose

有警告??可以使用-allow-warnings忽略。

4.5推送到本地LocalRepo

  • 使用了第三方庫(kù)
pod repo push driver_spec XXLibBase.podspec --allow-warnings --verbose --use-libraries
  • 未使用第三方庫(kù)
pod repo push driver_spec XXLibBase.podspec --allow-warnings --verbose

4.6pod lib lint 可選參數(shù)

pod lib lint SPEC_NAME.podspec
可選參數(shù):
--verbose : 顯示詳細(xì)信息
--allow-warnings: 是否允許警告,用到第三方框架時(shí)拌禾,用這個(gè)參數(shù)可以屏蔽講稿
--fail-fast: 在出現(xiàn)第一個(gè)錯(cuò)誤時(shí)就停止
--use-libraries:如果用到的第三方庫(kù)需要使用庫(kù)文件的話取胎,會(huì)用到這個(gè)參數(shù)
--sources:如果一個(gè)庫(kù)的podspec包含除了cocoapods倉(cāng)庫(kù)以外的其他庫(kù)的引用,則需要改參數(shù)指明湃窍,用逗號(hào)分隔闻蛀。
--subspec=Name:用來校驗(yàn)?zāi)硞€(gè)子模塊的情況。

注意:如果庫(kù)用到了第三方的話要帶上 --use-libraries您市,否則會(huì)報(bào)錯(cuò)觉痛,上傳不上去。

4.7--sources 使用

1.私有pod的驗(yàn)證

使用pod spec lint去驗(yàn)證私有庫(kù)能否通過驗(yàn)證時(shí)應(yīng)該茵休,應(yīng)該要添加--sources選項(xiàng)薪棒,不然會(huì)出現(xiàn)找不到repo的錯(cuò)誤。

pod spec lint --sources='私有倉(cāng)庫(kù)repo地址,https://github.com/CocoaPods/Specs'

2.私有庫(kù)引用私有庫(kù)的問題

在私有庫(kù)引用了私有庫(kù)的情況下榕莺,在驗(yàn)證和推送私有庫(kù)的情況下都要加上所有的資源地址盗尸,不然pod會(huì)默認(rèn)從官方repo查詢。

pod spec lint --sources='私有倉(cāng)庫(kù)repo地址,https://github.com/CocoaPods/Specs'
pod repo push 本地repo名 podspec名 --sources='私有倉(cāng)庫(kù)repo地址,https://github.com/CocoaPods/Specs'

4.組件化案例

1.效果圖

組件化案例.gif

2.代碼地址

https://gitee.com/Steven_Hu/hk-iostools

搬磚不易帽撑,轉(zhuǎn)載請(qǐng)注明出處,謝謝鞍时!

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末亏拉,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子逆巍,更是在濱河造成了極大的恐慌及塘,老刑警劉巖,帶你破解...
    沈念sama閱讀 222,000評(píng)論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件锐极,死亡現(xiàn)場(chǎng)離奇詭異笙僚,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)灵再,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,745評(píng)論 3 399
  • 文/潘曉璐 我一進(jìn)店門肋层,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人翎迁,你說我怎么就攤上這事栋猖。” “怎么了汪榔?”我有些...
    開封第一講書人閱讀 168,561評(píng)論 0 360
  • 文/不壞的土叔 我叫張陵蒲拉,是天一觀的道長(zhǎng)。 經(jīng)常有香客問我,道長(zhǎng)雌团,這世上最難降的妖魔是什么燃领? 我笑而不...
    開封第一講書人閱讀 59,782評(píng)論 1 298
  • 正文 為了忘掉前任,我火速辦了婚禮锦援,結(jié)果婚禮上猛蔽,老公的妹妹穿的比我還像新娘。我一直安慰自己雨涛,他們只是感情好枢舶,可當(dāng)我...
    茶點(diǎn)故事閱讀 68,798評(píng)論 6 397
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著替久,像睡著了一般凉泄。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上蚯根,一...
    開封第一講書人閱讀 52,394評(píng)論 1 310
  • 那天后众,我揣著相機(jī)與錄音,去河邊找鬼颅拦。 笑死蒂誉,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的距帅。 我是一名探鬼主播右锨,決...
    沈念sama閱讀 40,952評(píng)論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼碌秸!你這毒婦竟也來了绍移?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,852評(píng)論 0 276
  • 序言:老撾萬榮一對(duì)情侶失蹤讥电,失蹤者是張志新(化名)和其女友劉穎蹂窖,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體恩敌,經(jīng)...
    沈念sama閱讀 46,409評(píng)論 1 318
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡瞬测,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,483評(píng)論 3 341
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了纠炮。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片月趟。...
    茶點(diǎn)故事閱讀 40,615評(píng)論 1 352
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖恢口,靈堂內(nèi)的尸體忽然破棺而出狮斗,到底是詐尸還是另有隱情,我是刑警寧澤弧蝇,帶...
    沈念sama閱讀 36,303評(píng)論 5 350
  • 正文 年R本政府宣布碳褒,位于F島的核電站折砸,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏沙峻。R本人自食惡果不足惜睦授,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,979評(píng)論 3 334
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望摔寨。 院中可真熱鬧去枷,春花似錦、人聲如沸是复。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,470評(píng)論 0 24
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)淑廊。三九已至逗余,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間季惩,已是汗流浹背录粱。 一陣腳步聲響...
    開封第一講書人閱讀 33,571評(píng)論 1 272
  • 我被黑心中介騙來泰國(guó)打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留画拾,地道東北人啥繁。 一個(gè)月前我還...
    沈念sama閱讀 49,041評(píng)論 3 377
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像青抛,于是被迫代替她去往敵國(guó)和親旗闽。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,630評(píng)論 2 359

推薦閱讀更多精彩內(nèi)容