版本記錄
版本號 | 時間 |
---|---|
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
的使用,感興趣的給個贊或者關注~~~