iOS的组件化思路分享

栏目: IOS · 发布时间: 5年前

内容简介:iOS的组件化,一直都是一个理念,很多大公司一直在强调却没有具体可行的或简单可行的方案。所以分享下大概思路。框架说明:大致的框架思路,其中会碰到一个颗粒度的问题,将颗粒度设定过大,则组件之间的耦合性过大,颗粒度设定过小,则将产生很多的组件和中间组件,组件的管理成本过大。(具体问题需要具体分析)
iOS的组件化思路分享

iOS的组件化,一直都是一个理念,很多大公司一直在强调却没有具体可行的或简单可行的方案。所以分享下大概思路。

iOS的组件化思路分享

框架说明:

  1. 继续集成:一个主工程(壳工程),包含所有的内容(整个项目),用于发包或打包测试。
  2. 基础组件: 不依赖其他任何组件,独立完成功能。主要有:*与业务无法的功能(如string或data的加密,category的封装) *对第三方库的封装(如AFNetworking,SDWebImage的封装)
  3. 业务公用组件:依赖基础组件或UIKit等系统组件,创建业务共同使用的功能(如分享,支付,网络访问)
  4. 中间组件:连接业务公用组件和业务组件,及业务组件之间的互相调用。(如Mediator的组件)
  5. 业务组件:单独的业务功能,不依赖其他业务组件。

大致的框架思路,其中会碰到一个颗粒度的问题,将颗粒度设定过大,则组件之间的耦合性过大,颗粒度设定过小,则将产生很多的组件和中间组件,组件的管理成本过大。(具体问题需要具体分析)

一、 Cocoapods的组件管理

1. pod spec文件创建

spec文件说明

Pod::Spec.new do |spec| 
  spec.name = 'Reachability' spec.version = '3.1.0'
  spec.license = { :type => 'BSD' } 
  spec.homepage = 'https://github.com/tonymillion/Reachability' 
  spec.authors = { 'Tony Million' => 'tonymillion@gmail.com' } 
  spec.summary = 'ARC and GCD Compatible Reachability Class for iOS and OS X.' 
  spec.source = { :git => 'https://github.com/tonymillion/Reachability.git', :tag => 'v3.1.0' } 
  spec.source_files = 'Reachability.{h,m}' 
  spec.framework = 'SystemConfiguration'
end
复制代码

根据内容编写项目的信息,小的细节可以学习Git上支持Cocoapods的项目,查看项目中*.spec文件。 如: (1). 添加资源文件使用 s.resource_bundles (2). 需要添加多个文件,使用数组 s.source_files = ['ThirdSdk/Classes/**/*.{h,m}', 'ThirdSdk/Classes/**/**/*.{h,m}']

2. LICENSE和README.md文件

编写许可证和说明的文件。最好参考官方的写法,不然检测不过。

3.创建一个Example工程

关键一个Example的工程,在Podfile中采用直接引用Module文件进行组件的开发。 方便对单个组件进行调试pod 'ThirdSdk', :path => '../'

iOS的组件化思路分享

可以直接对Module进行修改,添加,删除等。

4.本地资料库(cocoapods镜像)创建

新建一个Git库,取名Specs用来保存本地的所有私有库。 使用 pod repo add [name] [Git地址] 添加一个私有Cocoapods Specs镜像。 使用 pod repo push REPO [NAME.podspec] 将私有组件推送到私有第三方库镜像。

5.依赖第三方库

在Podfile文件中可以添加依赖的第三方库,包括Cocoapods和私有本地的库。

platform :ios, '7.0'

source 'git@code.*.com:ios/Specs.git'

source 'https://github.com/CocoaPods/Specs.git'

target 'ThirdSdk_Example' do
  pod 'ThirdSdk', :path => '../'
  
  #cocoapods specs
  pod 'AliyunOSSiOS'
  
  #local specs
  pod 'WebService'
end
复制代码

其中

source 'git@code.*.com:ios/Specs.git'
source 'https://github.com/CocoaPods/Specs.git'
pod 'AliyunOSSiOS'
pod 'WebService'

二、组件之间的依赖

(1)对于基础组件的依赖,采用Pod 直接导致,在代码中进行import头文件。这个方式会导致基础组件的耦合性比较高。可以将组件的颗粒度设定的小一些,尽量抽取出不依赖其他组件的独立组件。再将这些独立的组件打包成一个较大的组件,方便管理。如Podfile中

#local specs
  pod 'Account'
  pod 'AppPod'
  pod 'WebService'
复制代码

其中的AppPod就是集合,包含很多独立的基础组件。

(2)如果是业务组件,在不同的业务之间,一定要避免组件间耦合,采用 Mediator 组件作为中间件,降低耦合。 具体可以参考[iOS应用架构谈 开篇]( casatwy.com/iosying-yon… ) 提供的Demo编写。

三、主工程

主工程(壳工程)引用所有的组件,并实现应用的工程。

iOS应用框架及Cocoapods内容的参考:

补充

1. 使用pod install 更新失败的处理

在使用Cocoapods管理代码的时候,如果在GitHut上更新了代码,希望在project中执行pod install 来刷新代码,那么需要 删除Pods和Podfile.lock文件 然后在执行pod install 来刷新代码

使用pod update进行repo的更新

多次安装pod install 会出现Build Phase里多个Check Pods Manifest.lock的选项,这些选项可以删除。

删除这个目录下的缓存文件,进行第三方库文件的重新获取/Users/*/Library/Caches/CocoaPods/Pods/*

因为有可能因为版本号,没有增加,在Pods目录下的VERSION保存了这个版本的第三方库,那么将直接返回已经缓存的文件。所以当私有组件有代码修改后,则可以清空这个文件夹下的目录,来进行私有组件的更新。:+1::+1::+1:(研究了很久才发现这个终极解决方法)

2. Pod中生成文件夹形式或创建子组件

在*.podspec文件中,根据功能创建不同的子组件,如AFN中的

s.subspec 'Security' do |ss|

ss.source_files = 'AFNetworking/AFSecurityPolicy.{h,m}'

ss.public_header_files = 'AFNetworking/AFSecurityPolicy.h'

ss.frameworks = 'Security'

end
复制代码

生成的效果

iOS的组件化思路分享

这种方式也是 子组件 的方法,在pod中可以直接引用AFSecurityPolicy的组件,如 pod 'AFNetworking/Security' 此时仅仅引用的是Security组件,而不是整个AFN组件

iOS的组件化思路分享

在开发是看到的组件,文件夹会比较乱,当其他组件pod后,看到的文件夹就如AFNetworking一样的效果。

3. *.podspec的dependency使用

组件可以依赖其他的第三方库,如 s.dependency 'JTObjectMapping' AFNetworking等。 同时也可以依赖私有的第三方库 : (1)使用 pod repo add [name] [Git地址] 添加一个私有Cocoapods Specs镜像。 (2)使用 pod repo push REPO [NAME.podspec] 将私有组件推送到私有第三方库镜像。 (3)在组件中就可以将已经上传的组件可以用来依赖了。

4. ThirdSdk组件

在ThirdSdk组件中,不能包含业务或项目相关的类,不然会导致互相依赖。仅仅包含第三方库的代码,可以降低耦合性。 如果能用Cocoapods管理的第三方库,尽量使用Cocoapods吧。

5. 加载静态库和framework

ss.vendored_frameworks = 'ThirdSdk/AlipaySDK/AlipaySDK.framework'
ss.vendored_libraries = 'ThirdSdk/AlipaySDK/libcrypto.a', 'ThirdSdk/AlipaySDK/libssl.a'
复制代码

a文件不是一个source_files。

6. runtime不能返回Bool等基础数据类型

return [target performSelector:action withObject:params];
复制代码

如果返回的值是Bool或其他的基础数据类型,那么将会 Crash

需要将返回值设置为NSObject对象类型或nil。

7. 组件中获取xib,png等resource时,bundle重新设置

NSBundle *bundle = [NSBundle bundleForClass:[self class]];
    NSString *bundlePath = [bundle pathForResource:@"StoreLocation" ofType:@"bundle"];
    if (bundlePath) {
        bundle = [NSBundle bundleWithPath:bundlePath];
    }
复制代码

其中StoreLocation是与podSpec中的s.resource_bundles里设置的保持一致。

s.resource_bundles = {
    'StoreLocation' => ['StoreLocation/Assets/**/*', 'StoreLocation/Classes/Address/*.{xib}'']
  }
复制代码

8. 图片和URL的处理

1、每一个组件需要用到的图片,都放到组件的Assets文件夹中。 在iOS8及更高系统,组件中Xib访问image会从组件的Assets中读取。但是iOS7系统,Xib还是从 [NSBundle mainBundle] 的Assets中读取文件。 2、URL 不单独放到一个头文件中,放入组件的ViewModel中。

9. TAG的刷新

当有多人合作开发,TAG又一直维持在1.0.0时,那么需要每次更新所有的TAG。

iOS的组件化思路分享
需要选中“ 抓取并在本地存储所有标签

”。

10. push 组件 *.podspec 文件

pod repo push Specs AppPod.podspec --allow-warnings
复制代码

推送时,如果一直报错,修护了Error还是一直报同样的Error,这时可以执行下 pod cache clean --all 清空缓存。

11. 不同configurations设置宏

当添加一个Ad-hoc的configuration,这个也需要设置DEBUG这个宏,并且在组件中也用到了DEBUG的宏定义,那么需要对所有的组件进行DEBUG的设置。方法如下

#设置Debug参数
post_install do |installer|

  installer.pods_project.targets.each do |target|

    target.build_configurations.each do |config|

      if config.name == 'Debug' 
       config.build_settings['GCC_PREPROCESSOR_DEFINITIONS'] = '$(inherited) DEBUG=1'
      
      end
      
      if config.name == 'Ad-hoc' 
       config.build_settings['GCC_PREPROCESSOR_DEFINITIONS'] = '$(inherited) DEBUG=1'
      
      end

end

end

end
#设置参数完成
复制代码

12. 更新OpenSSL失败

OpenSSL更新失败,可以删除/tmp/openssl 文件夹,重新尝试。

13. OpenSSL 的使用

在使用支付宝SDK时,会有引入OpenSSL文件夹,其中文件中使用 #include <openssl/e_os2.h> 。将SDK放入组件中,会报错,提示找不到文件。 解决方法: 在*.podspec文件中 添加 ss.header_dir = "openssl" 用来添加头文件夹openssl。

14. ARC 和 MRC 兼容

将使用MAC的放入subspec

s.subspec 'JTObjectMapping' do |ss|
    ss.source_files = 'StoreBase/Classes/JTObjectMapping/*.{h,m}'
    ss.public_header_files = 'StoreBase/Classes/JTObjectMapping/*.h'

    ss.requires_arc = false
  end
复制代码

因为JTObjectMapping第三方库使用的MRC所以特殊声明 ss.requires_arc = false . 在主spec中使用的ARC,则声明 ss.requires_arc = true . 此时主spec是ARC而JTObjectMapping是MRC,对JTObjectMapping中的文件都会添加一个-fno-objc-arc的编译宏。

15. 基础组件的版本更新

当主工程发布了版本,那么依赖的基础组件版本也固定,不能再做修改。当需要对基础组件进行修改,那么版本需要更新,版本号加一。 当某个基础组件A的版本号修改,那么依赖这个组件的所有组件BCD也都要修改版本。然后依赖BCD的组件EFG也要修改版本号,以此类推

16. 发布版本修改

发布版本修改:基础组件,将基础组件的所有依赖修改为大版本(如“=1.1.0”格式),必须指定版本号。比如有一个组件的版本号是1.0.5,那么这个版本进行了1.0.1到1.0.5的开发,在提交版本的需要修改1.1.0版本,并执行1.1.0版本。为了,(1)方便线上版本可以指定具体的版本。 (2)方便下一个版本的开发。 壳工程中,pod file文件的修改,将业务组件制定dev分支,修改为制定版本号,必须指定版本号。

业务组件的使用:开发时,podfile中直接dev分支获取代码,并在dev上进行开发。 等需要发布版本进行冒烟测试时,修改podfile为制定版本号。如“=1.1.0”。

pod 'Location', :git => 'git@code.xxx.com:ios/Location.git', :branch => 'dev'
复制代码

基础组件的使用在每个基础组件中,使用“~>1.0.3”进行开发,并在每次修改的时候,添加版本号。 基础组件依赖其他组件的时候,也修改为“~>1.0.3”, 那么在pod install的时候,就可以更新到最新的版本,不需要清理缓存。 发布版本的时候,在每一个组件中,指定版本号。如“=1.1.0”。保存每个发布的正式版本,都可以明确的知道所有组件的版本号。 发布版本后进行开发,那么需要修改依赖版本后“~>1.1.0”,不需要清理缓存,方便开发。 开发时,版本号的修改,仅仅针对需要修改的版本号。其他版本号保持不变。

图片资源创建一个图片资源的pod, 使用s.resources的方式进行添加图片。那么在xib中或imageNamed:"""直接可进行访问。不需要进行bundle的控制。:+1::+1::+1:

未完待续 // END


以上所述就是小编给大家介绍的《iOS的组件化思路分享》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

Charlotte's Web

Charlotte's Web

E. B. White / Puffin Classics / 2010-6-3 / GBP 6.99

This is the story of a little girl named Fern who loved a little pig named Wilbur and of Wilbur's dear friend, Charlotte A. Cavatica, a beautiful large grey spider. With the unlikely help of Templeton......一起来看看 《Charlotte's Web》 这本书的介绍吧!

SHA 加密
SHA 加密

SHA 加密工具

XML 在线格式化
XML 在线格式化

在线 XML 格式化压缩工具

HEX HSV 转换工具
HEX HSV 转换工具

HEX HSV 互换工具