版本记录
版本号 | 时间 |
---|---|
V1.0 | 2020.03.23 星期一 |
前言
在工程中,我们总要使用各种第三方依赖管理工具,方便我们进行管理。比如Cocoapods和Carthage等,这个模块我们就一起看一下这些第三方依赖管理工具。
开始
首先看下主要内容:
在本教程中,您将了解什么是
Carthage
,如何安装它,以及如何使用它来声明、安装和集成您的依赖项。
下面看下写作环境
Swift 5, iOS 13, Xcode 11
iOS开发的一大优点是可以使用广泛的第三方库。如果您尝试过其中的一些库,您就会知道使用其他人的代码而不是重新发明轮子的价值。
有这么多可用的库,管理依赖关系可能会变得很棘手。这就是依赖管理器(dependency managers)
的用武之地。
Carthage是一个简单的macOS
和iOS
依赖管理器,由GitHub
的一群开发人员创建。
Carthage
不仅是第一个与Swift
一起工作的依赖管理器,而且它也是用Swift
写的!它只使用动态框架,而不是静态库。
在本教程中,您将:
- 了解为什么以及何时使用依赖项管理器,以及
Carthage
与其他工具的不同之处。 - 安装
Carthage
。 - 声明依赖项,在项目中安装和集成它们。
- 将依赖项升级到不同的版本。
您将通过构建一个应用程序来实现这一点,该应用程序使用DuckDuckGo API
为搜索词提供定义。
打开初始项目,它包括DuckDuckDefine
的基本框架,这是一个使用DuckDuckGo API查找定义和图像的简单工具。有一个问题:它还没有执行任何搜索!
在Xcode
中打开DuckDuckDefine.xcodeproj
。注意两个视图控制器:SearchViewController
为用户执行搜索提供了一个搜索栏,DefinitionViewController
显示搜索项的定义。
这个操作的中心是在DuckDuckGo.swift
的——好吧,等你完成的时候他们就会敏捷了!目前,performSearch(for:completion:)
是一个懒惰的、无用的代码块。
要执行搜索并显示结果,您需要做两件事:
- 使用
DuckDuckGo API
进行查询。 - 显示检索到的单词的图像。
有许多开源库可以帮助完成这两项任务。Alamofire是一个很棒的Swift
库,可以简化web
请求。AlamofireImage使处理图像在Swift
更愉快。
你猜怎么着?您将使用Carthage
将这两个依赖项都添加到您的项目中。
Advantages of Dependency Management
要将Alamofire
和AlamofireImage
添加到您的项目中,您可以访问它们各自的GitHub
页面,下载包含它们的源代码的zip
文件并将它们放入您的项目中。为什么要用Carthage
这样的工具呢?
依赖管理器执行一些方便的函数,包括:
- 简化和标准化获取第三方代码并将其合并到您的项目中的过程。如果没有这个工具,您可以通过手动复制源代码文件、放入预编译的二进制文件或使用诸如
Git
子模块之类的机制来实现这一点。 - 使将来更新第三方库更加容易。想象一下,必须访问每个依赖项的
GitHub
页面,下载源代码,并在每次更新时将其放入项目中。你为什么要这样对自己? - 为您使用的每个依赖项选择适当的和兼容的版本。例如,当依赖项彼此依赖或共享另一个依赖项时,手动添加依赖项可能会很棘手。
大多数依赖关系管理器构建项目依赖关系及其子依赖关系的依赖关系图dependency graph,然后确定每个依赖关系的最佳版本。
你可以手工做同样的事情,依赖项管理器更简单,更不容易出错。
Comparing Dependency Managers
最流行的依赖项管理器之一是CocoaPods,它简化了将库集成到项目中的过程。它在iOS社区中被广泛使用。
苹果提供了自己的依赖管理器,叫做Swift包管理器Swift Package Manager,用于在Swift 3.0及以上版本中共享和分发包。
虽然CocoaPods
和Swift Package Manager
是很棒的工具,但Carthage
提供了一个更简单、更实用的选择。那么哪一个更适合你呢?在下一节中,您将比较Carthage
与其他一些流行的工具。
1. Carthage Versus CocoaPods
Carthage
与CocoaPods
有何不同?除了最受欢迎的iOS依赖管理器,你还会使用其他工具吗?
虽然CocoaPods
很容易使用,但并不简单。Carthage
背后的哲学是依赖管理器应该是简单的。
CocoaPods
增加了应用程序开发和库发布流程的复杂性:
- 库必须创建、更新和托管
Podspec
文件。如果应用程序开发人员希望使用的库不存在,他们必须编写自己的库。 - 当将
pod
添加到项目中时,CocoaPods
创建一个新的Xcode
项目,为每个单独的pod创建一个目标,并添加一个包含它们的工作空间。您必须使用工作空间,并相信CocoaPods
项目是有效的。您还必须维护那些额外的构建设置。 -
CocoaPods
使用一个集中的Podspecs
存储库。这可能会消失或变得无法访问,从而导致问题。
Carthage
的目标是提供一种更简单、更灵活、更容易理解和维护的工具。
Carthage
是这样做到的:
- 它不会改变您的
Xcode
项目,也不会强迫您使用工作空间。 - 您不需要
podspec
或一个集中式的存储库来存放库作者提交的pod。如果您可以将项目构建为框架,那么可以将其与Carthage
一起使用,Carthage
直接利用来自Git
和Xcode
的现有信息。 -
Carthage
并没有什么神奇的事;你总是在掌控一切。您将依赖项添加到Xcode项目中,然后Carthage获取并构建它们。
注意:
Carthage
使用动态库来实现其简单性。这意味着你的项目必须支持iOS 8或更高版本。
2. Carthage Versus Swift Package Manager
那么Carthage
和Swift Package Manager
有什么区别呢?
Swift Package Manager
的主要关注点是以一种对开发者友好的方式共享Swift代码。Carthage
的重点是共享动态库。动态库是Swift包的超集。
包是Swift源文件和manifest
文件的集合。清单文件定义包的名称及其内容。一个包包含Swift
代码、Objective-C
代码、图像等非代码资产或这三者的任何组合。
SPM
有很多优点,特别是Xcode 11
内置了对SPM
包的支持。然而,在撰写本文时,SPM有一些限制,使许多库无法支持它。例如,它不支持共享已经构建的二进制文件,只支持包的源代码。如果你想要一个闭源库,你不能使用SPM
。此外,SPM
支持向框架添加源代码,但不支持向图像或其他数据文件等资源添加源代码。
这意味着您可能使用的许多库都不会很快获得SPM支持。现在,您仍然需要依赖Carthage
或CocoaPods来实现这些库。
Installing Carthage
现在你已经获得了一些背景知识,是时候学习一下Carthage
是多么的简单了!
Carthage
的核心是一个命令行工具,它可以帮助获取和构建依赖项。
有两种方式来安装这个工具:
- 下载并运行最新版本的
.pkg
安装程序。 - 使用Homebrew软件包管理器。
就像Carthage
帮助安装用于Cocoa
开发的包一样,Homebrew
帮助安装用于macOS
的有用的Unix
工具。
出于本教程的目的,您将使用.pkg
安装程序。
从GitHub下载Carthage
的最新版本。然后,在Assets
下,选择Carthage.pkg
。
双击Carthage.pkg
来运行安装程序。单击Continue
,选择要安装到的位置,再次单击Continue
,最后单击Install
。
注意:当您尝试运行安装程序时,您可能会看到一条消息:
“Carthage.pkg can’t be opened because it is from an unidentified developer.”
。如果是,Control-click
安装程序,并从上下文菜单中选择Open
。
已经完成了,要检查Carthage
是否正确安装,请打开终端并运行以下命令:
carthage version
这将显示您安装的Carthage
版本。
接下来,您需要告诉Carthage
使用Cartfile
安装哪些库。
Creating Your First Cartfile
Cartfile
是一个简单的文本文件,它描述了您的项目对Carthage
的依赖关系,因此它可以决定安装什么。Cartfile
中的每一行都指明了在哪里获取一个依赖项,依赖项的名称,以及使用哪个版本。Cartfile
相当于CocoaPods Podfile
。
要创建第一个文件,请转到Terminal
,然后使用cd
命令导航到项目的根目录(包含.xcodeproj
文件的目录):
cd ~/Path/To/Starter/Project
使用touch
命令创建一个空的Cartfile
文件
touch Cartfile
然后在Xcode中打开文件进行编辑:
open -a Xcode Cartfile
如果您熟悉另一个文本编辑器,比如Vim
,那么可以随意使用它。但是,不要使用TextEdit
来编辑文件。在TextEdit中,很容易不小心使用“聪明的引号”而不是直接的引号,这会使Carthage
出现识别问题。
添加以下行到Cartfile
并保存:
github "Alamofire/Alamofire" == 4.9.0
github "Alamofire/AlamofireImage" ~> 3.4
这两行代码告诉Carthage
,您的项目需要Alamofire
版本4.9.0
和与版本3.4兼容的AlamofireImage
的最新版本。
The Cartfile Format
您可以在OGDL:Ordered Graph Data Language
的子集中编写cartfile
。这听起来很神奇,但其实很简单。在Cartfile
的每一行都有两个关键信息:
-
Dependency origin:这告诉
Carthage
在哪里获取依赖项。Carthage
支持两种起源:-
github:
github
用于github托管的项目(线索在名字里!)您可以使用Username/ProjectName
格式指定GitHub
项目,就像您在上面的Cartfile
中所做的那样。 -
git:用于托管在其他地方的通用
git
存储库。可以使用git
关键字,然后是git
存储库的路径,不管是使用git://、http://或ssh://
的远程URL,还是开发机器上git
存储库的本地路径。
-
github:
-
Dependency version:在这里,你告诉
Carthage
你想使用哪个依赖版本。根据你想要的具体程度,你可以有几种选择:- == 1.0:表示“完全使用1.0版本”。
- >= 1.0:表示“使用1.0或更高版本”。
- ~> 1.0:翻译过来是“使用与1.0兼容的任何版本”,意思是直到下一个主要版本的任何版本。
-
Branch name / tag name / commit name:意思是“使用这个特定的git分支/标签/提交”。例如,您可以指定
master
,或者像5c8a74a
这样的提交hash
值。
以下是一些例子:
如果你指定了~> 1.7.5
,Carthage
认为从1.7.5
到2.0
的任何版本都是兼容的,但不包括2.0
。
同样,如果您指定~> 2.0
,那么Carthage
将使用2.0版或任何后续版本,但不包括3.0
或以上版本。
Carthage
使用语义版本semantic versioning控制来确定兼容性。
如果您没有指定一个版本,Carthage
将使用与您的其他依赖项兼容的最新版本。你可以在Carthage
的自述文件 Carthage’s README file中看到这些选项的例子。
Building Dependencies
现在您已经有了一个Cartfile
,是时候使用它并安装一些依赖项了!
注意:这个
Carthage
教程使用的是Swift 5。在撰写本文时,Swift 5仅在Xcode 11
中可用。确保你已经配置你的命令行工具使用Xcode 11从终端运行以下命令:sudo xcode-select -s <path to Xcode 11>/Xcode.app/Contents/Developer
请确保将
path to Xcode 11
替换为您的机器到Xcode 11的特定路径。
在Xcode
中关闭你的Cartfile
,返回Terminal
。运行以下命令:
carthage update --platform iOS
这指示Carthage
从Cartfile
中克隆Git
存储库,然后将每个依赖项构建到框架中。您将看到显示结果的输出,如下所示:
*** Cloning AlamofireImage
*** Cloning Alamofire
*** Checking out Alamofire at "4.9.0"
*** Checking out AlamofireImage at "3.6.0"
*** xcodebuild output can be found in /var/folders/bj/3hftn5nn0qlfrs2tqrydgjc80000gn/T/carthage-xcodebuild.7MbtQO.log
*** Building scheme "Alamofire iOS" in Alamofire.xcworkspace
*** Building scheme "AlamofireImage iOS" in AlamofireImage.xcworkspace
--platform iOS
确保Carthage
只构建iOS框架。如果你不指定一个平台,Carthage
将为所有平台构建框架——通常是Mac
和iOS
——由库支持。
如果您想查看更多选项,请运行carthage help update
。
默认情况下,Carthage
执行它的checkout
并构建一个名为Carthage
的新目录,您将在与Cartfile
相同的位置找到它。现在打开这个目录运行:
open Carthage
您将看到出现一个Finder
窗口,其中包含两个目录:Build
和checkout
。花点时间看看Carthage
为你创造了什么。
Building Artifacts
当您使用CocoaPods
时,它会对Xcode
项目进行几处更改,并将结果与一个特殊的Pods
项目绑定到Xcode
工作空间中。
Carthage
有点不同。它检查依赖项的代码并将结果构建到二进制框架中。然后由您来将框架集成到您的项目中。
这听起来像是额外的工作,但它是有益的。只需几个步骤,您就可以更清楚地了解项目的变化。
当你运行carthage update
时,Carthage
会为你创建两个文件和目录:
-
Cartfile.resolved:此文件作为
Cartfile
的伙伴。它精确地定义了Carthage选择安装的依赖项版本。强烈建议将此文件提交到版本控制存储库。它的存在确保了其他开发人员可以通过使用完全相同的依赖项版本快速起步。 -
Carthage目录,包含两个子目录:
-
Build:它包含为每个依赖项构建的框架。您可以将这些集成到您的项目中,并且很快就会这样做。
Carthage
要么从源代码构建每个框架,要么从GitHub
上的项目发布页面下载框架。 -
Checkouts:这是
Carthage
签出每个准备构建到框架中的依赖项的源代码的地方。Carthage
维护它自己的内部依赖存储库缓存,因此它不必为不同的项目多次克隆相同的源。
-
Build:它包含为每个依赖项构建的框架。您可以将这些集成到您的项目中,并且很快就会这样做。
1. Avoiding Problems With Your Artifacts
您是否将Build
和Checkouts
文件夹提交到版本控制存储库取决于您自己。这不是必需的,但是这样做意味着任何克隆您的存储库的人都将拥有每个可用依赖项的二进制文件和源代码。
如果GitHub
不可用,或者源存储库被删除,有这个备份可能是一个有用的保险策略。
不要更改Checkouts
文件夹中的任何代码,因为将来的carthage update
或carthage checkout
命令可能会在任何时候覆盖其内容。你的努力工作一眨眼就会消失。
如果必须修改依赖项,请使--use-submodules
选项运行carthage update
。
通过这个选项,Carthage
将Checkouts
文件夹中的每个依赖项作为子模块添加到Git存储库中,这意味着您可以更改依赖项的源代码,并将这些更改提交到其他地方,而不必担心覆盖。
注意:如果其他开发人员使用您的项目,而您的代码还没有提交
built
框架,那么他们需要在检查完您的项目后运行carthage bootstrap
。
bootstrap
命令下载并构建在Cartfile.resolved
中指定的依赖项的精确版本。carthage update
将更新项目以使用每个依赖项的最新兼容版本,这可能是不可取的。
现在,如何实际使用这些您努力创建的构建工件呢?您将在下一节中完成这项工作。
Adding Frameworks to Your Project
回到Xcode
,在项目导航器中单击DuckDuckDefine
项目。选择DuckDuckDefine
目标。选择顶部的General
选项卡,然后滚动到底部的Frameworks, Libraries, and Embedded Content
部分。
在Carthage Finder
窗口中,导航到Build/iOS
。将Alamofire.framework
和AlamofireImage.framework
拖到Xcode
中的链接框架和库部分:
这告诉Xcode
将您的应用程序链接到这些框架,允许您在代码中使用它们。
接下来,切换到Build Phases
。单击编辑器左上方的+
图标,并选择New Run Script Phase
。在Run Script
下的代码块中添加以下命令:
/usr/local/bin/carthage copy-frameworks
点击Input Files
下的+
图标,为每个框架添加一个条目:
$(SRCROOT)/Carthage/Build/iOS/Alamofire.framework
$(SRCROOT)/Carthage/Build/iOS/AlamofireImage.framework
结果如下所示:
严格地说,这个构建阶段并不是您的项目运行所必需的。然而,对于一个App Store submission bug来说,这是一个巧妙的解决方案。在这个bug中,带有iOS模拟器二进制图像框架的应用程序会被自动拒绝。
carthage copy-frameworks
命令去掉了这些额外的体系架构。
尽管现在还没有什么新的东西可以看到,但是构建和运行以确保一切都如预期的那样工作。当应用启动时,你会看到搜索视图控制器。
好了。一切看起来不错。接下来,您将致力于升级依赖项。
Upgrading Frameworks
我要坦白一件事。
还记得你之前创建你的Cartfile
时,我告诉过你应该安装哪个版本的Alamofire
和AlamofireImage
吗?我给了你坏消息。我告诉过你用旧版本的Alamofire
。
别生气!我做这件事是出于好意。将此视为学习如何升级依赖项的机会。
再次打开你的Cartfile
。从你的项目的目录在终端,运行:
open -a Xcode Cartfile
改变Alamofire
那行
github "Alamofire/Alamofire" ~> 4.9.0
如前所述,此代码指示Carthage
使用与4.9.0
兼容的任何版本的Alamofire
。这包括任何版本,但不包括未来的5.0
版本。
在添加与Carthage
的依赖项时,您希望考虑兼容性并限制目标版本。这样,您就知道它的API和功能的确切状态。
例如,一个依赖项的5.0
版本可能包括破坏应用程序的API更改。如果您使用4.9.0
构建项目,就不会希望自动升级到该版本。
保存并关闭Cartfile
并返回到终端。执行另一个更新:
carthage update --platform iOS
这告诉Carthage
去寻找每个依赖项的更新版本。然后,如果需要,它将检查并构建它们。在本例中,它获取最新版本的Alamofire
。
因为您的项目已经包含了对Alamofire
构建的.framework
的引用,并且Carthage
在磁盘上的相同位置重新构建了新版本,所以您可以坐下来让Carthage
来做这项工作。您的项目将自动使用最新版本的Alamofire
!
Duck, Duck… GO!
现在您已经将Alamofire
和AlamofireImage
集成到项目中,您可以通过执行一些web
搜索来使用它们。
在Xcode
中,打开DuckDuckGo.swift
。在文件的顶部,添加下面的导入
import Alamofire
下面,用下面替换performSearch(for:completion:)
:
// 1
let parameters: Parameters = [
"q": term,
"format": "json",
"pretty": 1,
"no_html": 1,
"skip_disambig": 1
]
// 2
Alamofire.request(
"https://api.duckduckgo.com",
method: .get,
parameters: parameters)
.responseData { response in
// 3
guard
response.result.isSuccess,
let jsonData = response.result.value
else {
completion(nil)
return
}
// 4
let decoder = JSONDecoder()
guard
let definition = try? decoder.decode(Definition.self, from: jsonData),
definition.resultType == .article
else {
completion(nil)
return
}
completion(definition)
}
它的作用如下:
- 1) 首先,构建要发送给
DuckDuckGo
的参数。其中最重要的两个是q
(搜索项本身)和format
(格式),后者告诉web
服务使用JSON
响应。 - 2) 然后使用
Alamofire
执行请求。这个调用使用上面创建的参数字典向https://api.duckduckgo.com
发出一个GET
请求。 - 3) 一旦响应返回,检查请求是否失败,并绑定JSON响应对象以确保它有一个值。如果出了问题,尽早退出。
- 4) 接下来,使用
JSONDecoder
对定义进行反序列化,这遵循Codable
协议。DuckDuckGo API
可以返回一系列不同的结果类型,但是这里介绍的是Article
,它提供了搜索词的简单定义。筛选文章,然后将检索到的定义传递给完成处理程序。
注意:如果你想知道为什么
skip_disambig
参数存在,它是告诉DuckDuckGo
不要返回disambiguation
结果。消除歧义的结果就像维基百科上克里斯·埃文斯this Christopher Evans page on Wikipedia的页面一样,需要说明的是无论你指的是电影演员克里斯·埃文斯,英国电视名人克里斯·埃文斯还是火车劫匪克里斯·埃文斯。
skip_disambig
意味着API将选择最可能的结果并返回它。
构建和运行。一旦应用程序启动,在搜索栏中输入“Duck”
。您将在下一个屏幕上看到定义。
然而,少了一样东西:一张照片!读鸭子是一回事,但谁还会读呢?照片是有价值的——好吧,我就不啰嗦了,你知道我的意思。
打开DefinitionViewController.swift
并在顶部现有的UIKit
导入下面添加一个新的导入:
import AlamofireImage
在viewDidLoad
下面添加下面代码:
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
if let imageURL = definition.imageURL {
imageView.af_setImage(withURL: imageURL) { _ in
self.activityIndicatorView.stopAnimating()
}
}
}
af_setImage
是AlamofireImage
提供的UIImageView
的扩展。您可以调用它来检索在定义imageURL
中找到的图像。检索后,活动指示器的动画将停止。
构建并运行,然后再次执行搜索。
如果你想更多地了解Carthage
,你的第一站应该是 Carthage README和关于Build Artifacts的文档。
最后,如果你想了解更多关于Swift Package Manager的信息。
后记
本篇主要讲述了
Carthage
的使用,感兴趣的给个赞或者关注~~~