[遷移背景故事]:
國慶前把之前一個已經發(fā)布的工程改了下配置重新上架纳像,結果編譯死活通過不了窖张,報的錯主要是Segmentation fault: 11
與Command CompileSwift falied with a nonzero exit code :
,項目初次遇到這個問題時是在第一次打包時遍愿,當時查閱資料說是 Xcode 的 Bug 清除緩存重新編譯就順利上線了存淫。這次網上各種方法試了個遍都沒效果,好在是個小工程不復雜沼填,項目在做模塊化的時候使用 CocoaPods 配合 framework 拆分了基礎模塊和公共業(yè)務。最后迫不得已將分拆的基礎模塊又導入回主工程下括授,再次編譯坞笙,發(fā)現(xiàn)是 MJRefresh 給組件附加的 header 和 footer 在調用時沒有加上可選標識的問號,修復后編譯通過荚虚。
推測是因為 MJRefresh 由 Objective-C 編寫而成薛夜,之前的版本可能是舊版本 Xcode 對 OC 類型進行
可選檢查
沒有深入到子模塊,最新版本的 Xcode 新增了對 OC 對象更深入的檢查卻沒有對子模塊響應的提示版述,以至于我們打開 Swift 報錯檢查等操作并沒有具體信息梯澜。好巧不巧,這幾天鼓搗了下 SwiftPM 后渴析,這個為上架被迫臨時還原的項目正好可以拿來試試 SwiftPM 的成色如何晚伙。本文記錄了該工程從 CocoaPods 遷移到 SwiftPM 過程中遇到的問題以及解決辦法。
[閱讀難度:簡單]
以筆者的小工程為例俭茧,CocoaPods 導入的三方庫大約十來個咆疗,包含了Swift與OC兩種類型的庫,這些庫對 SwiftPM(Swift Package Mananger)的適配狀態(tài)也不盡相同母债。遷移的過程從最簡單的情況開始一個一個解決午磁。
Swift 類型的庫
Swift 類型的庫屬于最簡單的情況,直接用 SwiftPM 引入即可毡们,諸如 Alamofire
迅皇、Kingfisher
、SnapKit
等庫衙熔。對 Xcode 中如何使用SwiftPM 還不了解的同學可以參考官方文檔或者 上一篇文章
Objective-C 類型的庫
SwiftPM 本是專門針對 Swift 誕生的登颓,由于歷史原因,很多庫是由OC編寫而成青责,如何引入OC的包挺据?可以分為兩種情況:
1. 支持 SwiftPM 的庫
這一類跟Swift的庫一樣直接導入就可以了取具,這里可以借鑒 MBProgressHUD 庫的官方實現(xiàn),在其 Package.swift
文件中配置如下:
import PackageDescription
let package = Package(
name: "MBProgressHUD",
products: [
.library(name: "MBProgressHUD", targets: ["MBProgressHUD"])
],
targets: [
.target(
name: "MBProgressHUD",
dependencies: [],
path: ".",
exclude: ["Demo"],
sources: ["MBProgressHUD.h", "MBProgressHUD.m"],
publicHeadersPath: "include"
)
]
)
大體和 Swift 庫一致扁耐,特別注意 sources
這里暇检,庫的 OC 文件都列在了這里,publicHeadersPath
則是需要公開的頭文件目錄婉称,自定義OC庫想了解詳細設置可查看官方文檔或參考 MBProgressHUD
的實現(xiàn)块仆。
但這種方式有個問題,對于MBProgressHUD這樣個位數(shù)文件的OC庫實行起來倒是沒什么影響王暗,如果是 MJRefresh 這樣幾十個文件還附帶資源文件怎么辦悔据?可能這也是MJRefresh到目前為止依舊沒有適配SwiftPM的原因之一。(在最新的 Swift5.3 中已經支持導入資源文件俗壹,SE-0271)
2. 未支持 SwiftPM 的 OC 庫
最直接的方法是自己創(chuàng)建一個 Swift Package 的中間庫科汗,自行配置Package.swift與各種文件。就像上面說的绷雏,這種方法耗費太多的時間头滔,隨著庫的發(fā)展,三方庫大改涎显,中間庫的配置就要大改坤检,想到這里腸胃一陣蠕動, Pass期吓。
那就曲線救國早歇,在 Swift 為主的工程中,引入的 OC 庫都比較少讨勤,且都是經得起時間考驗的精品庫箭跳,沒有適配 SwiftPM 的就更少了⌒螅可以將這類 OC 庫打包成 Framework 直接丟進項目中即可衅码。這里筆者借助了 CocoaPods 的一個插件 cocoapods-binary,因為CocoaPods在安裝三方庫時會將其所以來的庫一并安裝脊岳,省去不少麻煩逝段。具體過程如下:
1. 安裝 cocoapods-binary:
$ gem install cocoapods-binary
2. 新建個空工程。
3. 創(chuàng)建Pod文件(以MJRefresh為例):
source 'https://github.com/CocoaPods/Specs.git'
platform :ios, '13.0' // 這里改為指定系統(tǒng)版本
inhibit_all_warnings!
use_frameworks! // 動態(tài)庫
plugin 'cocoapods-binary' // 插件
all_binary! // 插件應用于全部庫
abstract_target 'BASE_POD' do
pod 'MJRefresh'
target 'StaticLibDemo' do
project 'StaticLibDemo.xcodeproj'
workspace 'StaticLibDemo.xcworkspace'
end
end
4.在當前工程下調用 pod install
命令
**5.生成的庫在生成的 Pods 文件下割捅,路徑為: **
/Pod/_Prebuild/GeneratedFrameworks/
6.將其中生成的庫復制到我們的項目中(如:MJRefresh.framework奶躯,僅僅是framework,別的不要亿驾,否則發(fā)布報錯)
這里生成的庫會有 x86_32
架構嘹黔,在發(fā)布時會報 IPA progress fail
,需要將此架構從庫中移除。
具體方法:
- 命令面板跳轉到framework:
$ cd /XXX/XXXX/包名.framework
- 查看信息:
$ lipo -info 包名
儡蔓,這里會顯示出 i386郭蕉、x86_64- 移除:
$ lipo -remove i386 包名 -o 包名
$ lipo -remove x86_64 包名 -o 包名
- 再次查看信息確認移除成功后即可將包導入工程。
7.因為我們生成的是動態(tài)庫喂江,所以別忘了在 General 中將導入的動態(tài)庫設置為“embed & sign”
至此召锈,我們就可以正常替換之前在 CocoaPods 引入的 MJRefresh 了,這只是權宜之計获询,有更好的辦法的小伙伴歡迎補充 [猛男微笑.gif]涨岁。
遇到的問題
用 SwiftPM 導入庫后,編譯報錯 not found 'xxxxx'
建議備份一下工程吉嚣,這類錯誤的原因不一定相同梢薪。
筆者解決方法:通過刪除 Build setting 下 Other Linking 的所有配置可編譯正常
RxSwift 的導入問題
因為工程以來的基礎模塊應用到了 RxSwift 所以基礎模塊的SwiftPackage依賴于RxSwift,然而這個庫目前(20201015)對SwiftPM的支持是有問題的(相關鏈接)尝哆。而這導致使用 RxSwift 給出的配置來配置項目時秉撇,Xcode無法識別,也無法在
按照官方方法配置子模塊的 Package.swift:
import PackageDescription
let package = Package(
name: "RJSuger",
platforms: [.iOS(.v13)],
products: [
.library(
name: "RJSuger",
targets: ["RJSuger"]),
.library(
name: "RJBaseWidgets",
targets: ["RJBaseWidgets"]),
],
dependencies: [
.package(url: "https://github.com/SnapKit/SnapKit.git", .upToNextMajor(from: "5.0.1")),
.package(url: "https://github.com/ReactiveX/RxSwift.git", .exact("6.0.0-rc.1"))
],
targets: [
.target(
name: "RJSuger",
dependencies:[],
path: "Sources/RJSuger"),
.target(
name: "RJBaseWidgets",
dependencies: ["RJSuger","SnapKit","RxSwift", "RxCocoa"],
path: "Sources/RJBaseWidgets"),
.testTarget(
name: "RJSugerTests",
dependencies: ["RJSuger"]),
],
swiftLanguageVersions: [.v5]
)
這樣的配置對于筆者的模塊较解,Xcode 識別不出來畜疾,報出來的錯誤指向了 最后添加的依賴項 RxCocoa,參考 RxSwift的文件結構是RxSwift下有 RxSwift印衔、RxCocoa、RxRelay等模塊姥敛,嘗試性的將對應的 Targets 依賴變更為:
//····
dependencies: ["RJSuger","SnapKit",.product(name: "RxSwift", package: "RxSwift"),.product(name: "RxCocoa", package: "RxSwift")],
//···
編譯通過奸焙。
總結
從 2018 年推出 SwiftPM 到現(xiàn)在,SwiftPM 已經可以應付大部分庫管理的場景彤敛,對自定義模塊的支持也不錯与帆,不出問題的時候使用起來真是清爽自然。而當遇到問題時墨榄,網絡上資料可能很少玄糟,也可能直接就是三方庫或 SwiftPM 本身的問題不得不另尋他法。最最最重要的問題是加載庫的速度和機制
袄秩,稍微大點的庫本身速度就慢阵翎,稍微變動下工程結構,SwiftPM 就莫名所有庫重新加載一次之剧,導致大量時間浪費在這上面郭卫,而SwiftPM 的 checkout 下來的庫對存在 DriveData/工程文件/SourcePackages/checkout下
,對于老夫這種喜歡清理 DriveData 的人不得不備份一份在其抽風時替換背稼。
所以個人建議:SwiftPM 建議了解下贰军,實際應用到項目,膽子小的:
再等一年又何妨
Thanks for reading :)