「这是我参与2022首次更文挑战的第1天,活动详情查看:2022首次更文挑战」。

为什么要组件化

组件化一般是把工程分层拆成不同的组件,以达到解耦,模块复用,便于单元测试,编译速度优化等效果,最索引的作用终目的是为了提高开发质量和效率。当然,组件化是有一定成本的,在组件化之前要考虑清楚当前的项目情况是否适合组件化,收益能否覆盖开发成本。规模较小,模块没太多复用需求的项目,就没必要进行组件化。

组件化如何缓存视频合并app下载分层

组件化之前,先要对项目进行分层,以我们现在的项目为例:

iOS组件化避坑心得

分层后,一般使用Cocoapods来封装组件,通过路由来进行不同业务模块间的解耦调用。其中系统框架层公有httpclientpod库层是本来就有的。其它层的拆分逻辑分别是:

  • 自有公有组件swiftkey层(公有pod):这一层的pod都是推到公有仓库,和业务是没有任何耦合的的,就是用swiftkey于放开源的组件。
  • 私有组件层(私有pod):这一层的组件都有自己的私有git仓库,缓存的视频怎么保存到本地通过私有git仓库和私有索引库来进行管理,根据实际业务场景,这一层可能还会再进行分层。一般放一些项目中http 404比较基础和通用的逻辑,例如配置信息管理,埋https协议点管理,数据存储这些。
  • 本地组件层(本地pod):这一层放业务模块,是app呈现给用户的一个模块的整体封装,例如我的模块缓存视频合并,首页模块这类。它的修改会非索引是什么意思常频繁,日常的业务开发大部分都是在这一层,所以使用本地pod的方式,不会单独创建git仓库,与主工程共用一个git仓库进行管理。

cocoapods只支持在Podfile中以path方式依赖pod,在podspec中是不支持的,所以本地pod最多只能有一层。(你也可以写插件支持多层)

这样分层后,当http 500有新https域名的业务需求时,我们只需要创建一个本地pod,写入pod依赖,就可以快速的缓存是什么意思进入业务开发状态,因为没有其它模块的干扰,编译和调试的速度会得到极大的提升,同时也避免了模块之间的耦合。

使用Cocoapods制作不同类型的组件

通过上述内容,索引符号可以知道有三种类型的组件:公有pohttp代理d私有pod,本地swiftcode代码查询pod。不管什么类型,都建议使用pod lib create PodName命令来创建组件,在它生成的组件模版基础上,可以很方便的http://192.168.1.1登录进行swift翻译开发。

公有Pod

公有pod是面向所有开发者的,需要尽量保证它的可用性和稳定性swift是什么意思啊。如何发布公有pod这里不做说明,可以参考官方文档:Getting setup with T缓存文件夹名称runk。一些公司提供的商用公有pod,连pod验证命令pod lib li缓存文件夹名称ntswift系统都无法通过,这个是不应swift代码该的,最容易出现的问题https认证就是编译错误,因为它会校验各个场景,而很多pod开发者却只保证自己的pod在常见场景可用。常见的报错有:

// 报错1:
ld: symbol(s) not found for architecture i386
// 报错2:
building for iOS Simulator, but linking in object file built for iOS, file 'you path' for architecture arm64

这里的i38632位模拟器的架构,arm64m1机型上的模拟器架构,出现这种问题一般是pod中引入了lib或者framework静态库,而这些库不支持这些架构。 现在都2202年了,微信的最低支持版本都到了12.0,所以请大胆将pod库的deployment_taswift是什么意思啊rget参数设置为缓存视频怎样转入本地视频12.0,这样就不会进行i386架构的验证。 而对arm64模拟器架构的支持,最好是将静态库重新打包成.xcframework缓存视频怎样转入本地视频格式并支持arm64模拟器架构,不然会导致m1设备的使swiftkey用者只能以Rohttp 500setta模式在模拟http代理器上运行项目。具体可httpclient以看我之前写的博文M1设备的Xcode编译问题深究 ,如这些静态库是第三方提缓存供的,无法重新打包支持arm64模拟器架构,则可以进行如下设置避免报错:

# 因为依赖的静态库不支持模拟器arm64架构,设置当前这个pod不支持arm64, 以避免pod lib lint无法通过
s.pod_target_xcconfig = { 'EXCLUDED_ARCHS[sdk=iphonesimulator*]' => 'arm64' }
# 单纯设置pod_target_xcconfig只是设置当前这个pod不支持arm64, 这里把这些pod的上层设置为不支持arm64,兼容这种问题
s.user_target_xcconfig = { 'EXCLUDED_ARCHS[sdk=iphonesimulator*]' => 'arm64' }

对于公有pod,负责任的做法是没有任何错误和警告后再进行发布,如果由于各种客观原因,实在无法去除警告,可以加入--allow-warnings参数来推送:pod trunk push [NAME.podspec] --allow-warnings。如果添加--skip-import-validation参数来逃避验证,则显http://192.168.1.1登录得有些不负责任了。

另外,在Chttps认证ocoaPods1.8版本,将默认的spec repo设为了CDN源,以提高pod的速度。刚发布的公有pod版本,可能要几个小时后才能被同步到CDN缓存视频变成本地视频,导https协议致刚发布时调用pod install --repo-update没法找到新发布的podhttpclient库,这时可以通过指定源来解决https和http的区别这个问题,样例如下:

pod '你的公有pod', :source => 'https://github.com/CocoaPods/Specs'

当然,CDN源同步后要记得改回。

私有Pod

私有pod一般通过私有reposwift代码进行管理,这样才方便做版本管理和使用缓存私有repo创建命令是pod repo add REPO_NAME SOURCE_URL,其中SOURCE_URL就是私有rep索引的作用o的git地址。创建私有repo后,通过pod repo push REPO_NAME索引超出了数组界限什么意思 SPEC_NAME.podspec命令来发布私有pod私有repo。需要注意的是私有pod公有pod的发布命令并不一样,分别是:

# 公有pod发布命令
pod trunk push SPEC_NAME.podspec
# 私有pod发布命令
pod repo push REPO_NAME SPEC_NAME.podspec

发布后,需要在PodfileHTTPS加入私有repo源,才能找到私有pod并安装成功。

# --- Podfile文件 --
# 指定私有source
source 'https://youhost.com/YouPrivateRepo.git'
# 指定公有source,
source 'https://github.com/CocoaPods/Specs.git'

这些固定流程不做过多说明,具体内容可以查看官方文档:Private Pods

如果私有pod中依赖了非公有源的pod,在pod lib linhttp代理t时会出现这类报错:

ERROR | [iOS] unknown: Encountered an unknown error (Unable to find a specification for `AlicloudHTTPDNS` depended upon by `DTHttpDns`

这时根据提示调用pod repo update后也是无效的,这类问题可以通过指定sources来解决,以如上报错为例,它依赖的AlicloudHTTPDNS是阿里的源:https://github.com/aliyun/aliyun-specs.gihttps域名t,设置sourcesswift怎么读则可以验证通过:

# 可以通过逗号分隔,添加多个不同的source。(--sources='a_source,b_source')
pod lib lint DTHttpDns.podspec --allow-warnings --sources='https://github.com/aliyun/aliyun-specs.git'

pod repo push也可能会出现上述报错,但是它的逻辑稍有不同,它会从你缓存视频怎样转入相册本地的repo列表中去查找pod依赖,找到则不会报错。而pod lib lint在没有指定sources时,只会从默认的源去找。

本地Pod

本地pod与主工程一起被同一个git仓库管理,不需要单独进行版本管理,也不需要p缓存视频合并ush,而是在Podfile中直接以path的方式进行引入,样索引超出了数组界限什么意思例如下:

# --- Podfile文件中 --
pod '你的本地pod', :path => '../本地pod路径/你的本地pod目录名'

Pod组件索引超出了数组界限什么意思中使用资源的坑

在pod中,经常会出现需要https认证使用图片,xib,json文件等资源的场景,建议使用resource_bundles来配置使用这些资源,以名为DTVideo的pod库为例:

# -- DTVideo.podspec 文件中--
s.resource_bundles = {
      'DTVideoAssets' => ['DTVideo/{Assets,Classes}/**/*.{xib,xcassets}']
  }

这样配置后,cocoapods会自动把这些资源打包成一个名叫DTVideohttp代理Assetsbundle文件,在pod中使用这些资源的方式会发生一些改变。假如这个pod中有一swiftly个类VideoP索引符号和详图符号layLSwiftistCell.swift,那么我们可以创建辅助方法:

struct DTVideoCommon {
    static func assetsBundle() -> Bundle? {
        let myBundle = Bundle(for: VideoPlayListCell.self)
        let path = myBundle.path(forResource: "DTVideoAssets", ofType: "bundle")
        guard let path = path else {
            return nil
        }
        let assetsBundle = Bundle.init(path: path)
        return assetsBundle
    }
    static func imageWith(named name: String) -> UIImage? {
        let assetsBundle = assetsBundle()
        let image = UIImage.init(named: name, in: assetsBundle, compatibleWith: nil)
        return image
    }
}

加载图片时:

let image = DTVideoCommon.imageWith(named: "video_play_max_nor")
imageView.image = image

使用xib时:

let cellNib = UINib.init(nibName: cellIdentifier, bundle: DTVideoCommon.assetsBundle())
tableView.register(cellNib, forCellReuseIdentifier: cellIdentifier)

xib文件http 500中设置Module名的坑

xib文件中有Module缓存清理置,如果是在工程中创建的,那么它默认是勾选上inherit Module From Tswiftkeyarget,当将这个文件移动到pod中时,https协议它的Module名就被设置成了默认名,缓存文件夹名称bundle名,这样会导致创建这个chttp 404ell的时候报错:

Terminating app due to uncaught exception 'NSUnknownKeyException', reason: '[<UITableViewCell 0x7fd3eba23d60> setValue:forUndefinedKey:]: this class is not key value coding-compliant for the key you_error_key.'

错误设置图示如下:

iOS组件化避坑心得

正确的设置是不要勾选inherit Module From Target,并且在Module缓存是什么意思栏输入正确的Module名

当然你也可以空着,不输入Module名,但是这样需要修改ViswiftlydeoPlayListCell的类名:

@objc(VideoPlayListCell) // Module栏空着情况下,必须添加这行
class VideoPlayListCell: UITableViewCell {
	// ... 代码省略
}

如果不使用@objc(VideoPlayListCell)修改类名,那么会出现上面一样的报错,所以还是建议输入正确的Module名

关于module

cocoapods现在默认会开启pod库的mhttpclientodule选项,所以没有必要在podspec中配置:'DEFINES_MODULE' => 'YES'

iOS组件化避坑心得
module对头文件的引入和混编做了很大的优化,在引入其它组件的时候,建议以@import或者#im索引颜色模式包含多少种颜色port <A/A.h>的方式引入,其中#import <A/A.h>索引超出了数组界限什么意思httpclient最终转换为@import的方式。

现在使用pod库,以#imporhttps域名t "XXX索引的作用"#impo索引符号rt <XXX>的方式引入,Xcode都没有补全提示了,只https域名@https和http的区别import方式有。

如果想对module做更多的了解,建议看这篇博文https协议:从预编译的角度理解Swift与Obje缓存是什么意思ctive-C及混编机制,这篇博文写的索引失效的几种情况和解决非常好,内容也很长,阅http 302读完索引失效的几种情况和解决需要一两个小时。后面的内容很多是对篇博文的部分总结和回顾,再次感谢这篇博文的作者。

pod库中swift与Objective-C的混编问题

SwiftObjective-C文件同时在一个App或者Unit Test类型的Target中,不同类型文件的API寻找机制如下:

iOS组件化避坑心得

这个和pod没有关联,是主工程的混编用法。

SwiftObjective-C文件在不同Target中,例如不同Frameworkhttpclient中,不同类型文件的API寻找机制如下:

iOS组件化避坑心得

图示的module.modulemap指的是需要缓存视频变成本地视频import不同frameworHTTPSkmodule,例如Apod中的swift文件需要引用Bpod中的.h/.m文件,需要:import B

SwiftObjective-Chttp://www.baidu.com件同时在一个Target中,例如同一Frahttp协议meswift翻译work缓存文件夹名称,不同类型文件的API寻找机制如下:

iOS组件化避坑心得

这代表在同一个pod库索引颜色模式包含多少种颜色中,不需要做任何处理,swift就可以直接调用库中的oc代码。但是oc想调用索引超出了数组界限什么意思库中的swift代码,则需要导入固定格式的头文件,如:#import <DTVideo/DTVideo-http://192.168.1.1登录Swift.h>,其中DTVideo就是这个pod库的module名。另外还索引失效的几种情况和解决有两个点需要注意:

  • swift中必须是声明为public或者open权限的才能被同一个pod中的oc代码或swiftly者外部调用。
  • 如果想在pod外部创建它某个swift类子类,那么这个swift类必须声明为open权限

pod中swift使用struct的坑

struct默认生成的初始化方法http 302internal级别的,例如:

public struct TestStruct {
    let key: String
}
func test() {
    TestStruct(key: "aaaa")
}

它可缓存视频变成本地视频以在pod里面调用,但是在pod外部被调索引失效的几种情况和解决用则会报错:'TestStruct' initializer is inaccessible due to 'internal' protection level。 需要手动创建它的public init方法。如缓存

public struct TestStruct {
    let key: String
    // 需要手动添加public init方法
    public init(key: String) {
        self.key= key
    }
}

Swift置pod库的Public HeadersPrivete Headers

构建产物为Framework的情况缓存视频在手机哪里找

  • 根据podspec里的public_header_fileshttps域名字段的内容,将相应头文件设置为Pubhttpclientlic类型,并放在Headers中。
  • 根据podspec里的prhttp 404ivate_head索引的作用er_files字段的内容,将相应文件设置为Private类型,并放在PrivateHeswift怎么读ader中。
  • 将其余未描述的头文件设置为Project类型,且不放入最http 404终的产物中。

如果podspec里未标注P索引超出矩阵维度ublicPrivate的时候,会将所有文件设置为Public类型,并放在Header中。

构建产物为Static Library的情况下

不论podspec里如何缓存视频在手机哪里找设置public_header_filesprivate_header_files,相应的头文件都会被设置为Project类型。

  • Pods/Headers/Public中会保存所有被声明为public_header_files的头文件。
  • Pods/Headers/Private中会保存所有头文件,不论是public_header_files或者 private_header_files描述到,还是那些未被描述的,这个目录下是当前组件的所有头文件全集。

关于路由

现在常见的路由方案有:URLRouteProtocol-ClassTarget-Action等。个人偏爱URLRoute,主http协议要有两方面的原因:

  • 第一是通用索引是什么意思URLRoute可以多端统一,例如运营配置一条推送,点击打开某个页面,对于运Swift营方来说,统一配置固定规则的URL就可以了,每个端都一致。H5页面要打开某个Native页面索引的作用,或者外部唤起,也是统一用URLRoute就可以了,不需要区分平台做不同操作。索引超出矩阵维度
  • 第二是没法避开。例如UswiftkeyRL SchemeUniversal Links这类,还是需要使用到URL

Protocol-ClassT索引超出矩阵维度arget-Action这些方案,没法避免硬编码,只能说是URLRoute的一种补充。URLSwiftRoute本质上就是约定一个各端通用的协议,在各端内部对协议进行正确的解析和逻辑处swiftkey理。封装好http 500了之后,不管是外部还是内部的调用者,不需要索引图关心任何细节索引失效的几种情况和解决和区分平台,只需要传入协swift翻译议就可以。综上所属,推荐使用URLRouteswift代码

关于脚本

组件化后会多出很多重复简单的操作,例如一个私有pod的新版本发布,需要的流程有:git commit -> 打tag -> pod验证 -> pod发布,这些都是可以通过编写脚本简化操作的,建议在组件化过程中多做这方面的工作。

后文

现在市面上的组件化方案很多,各大公司各种高大上的落地方案。我在小公司的业务间隙,抽时间写的这篇简单的避坑心得,是对自己实践的整理和归纳,希望能帮到你。

参考资料

  • 从预编译的角度理解Swift与Ob索引是什么意思jechttpclienttive-C及混编机制
  • iOS 组件化 —— 路由设计思路分析

by:星的天空