[譯] 從現有的代碼庫建立 Swift 包管理器

Swift 包管理器(SPM)很是適合編寫快速工具,你甚至能夠從應用程序中提取現有代碼。訣竅是你須要意識到你能夠將文件夾符號連接到 SPM 項目中,這意味着經過一些工做你能夠建立一個包裝生產代碼部分的命令行工具。前端

你爲何要這麼作?

雖然它很依賴於項目,可是常見的用例是建立支持、調試和持續集成(CI)驗證工具。例如,許多應用程序爲了實現功能而使用遠端的數據,應用程序須要將遠程數據轉換爲自定義的類型,而且使用業務規則對此數據執行有用的操做。在此流程中會有多個故障點顯示出應用程序的崩潰或不正確的行爲,所以解決的方法是在有附加調試器的狀況下啓動並進行調試,Swift 包管理器將是一個幫助發現問題並潛在地阻止問題的好工具。android

注意事項

你不能使用 UIKit 框架的下的代碼,由於這項技術僅適用於基於 Foundation 庫的代碼。雖然這聽起來有限制,可是在理想狀況下,業務邏輯和數據操做的代碼都不該該都不該該引入有關 UIKit 框架下的東西。ios

具備依賴性致使了該技術更加難,不過你仍然能夠使用它,可是須要在 Package.swift 中進行更多的配置。git

你要怎麼作呢?

這取決於你的項目結構。我這裏有一個示例項目。這是一個小型的 iOS 項目,它顯示了一個博客的帖子列表(你並不須要看項目自己,項目自己並不重要)。項目中博客的帖子來自於假的 JSON 數據,它沒有特別好的結構,所以應用程序須要進行自定義解碼。爲了保持它的輕量級,我將如下面的方式構建最簡單的包裝器:github

  • 從標準輸入中讀取
  • 使用生產解析代碼
  • 打印解碼結果或錯誤

你能夠瘋狂地給它添加更多的更能,可是這個簡單的工具將會讓咱們在不啓動模擬器的狀況下,快速爲咱們提供關於生產代碼是否能夠接受某些 JSON 的反饋或者顯示任何可能發生的錯誤。web

這個示例項目的基礎結構以下:swift

.
└── SymlinkedSPMExample
    ├── AppDelegate.swift
    ├── Base.lproj
    │   └── LaunchScreen.storyboard
    ├── Info.plist
    ├── ViewController.swift
    └── WebService
        ├── Server.swift
        └── Types
            ├── BlogPost.swift
            └── BlogPostsRequest.swift
複製代碼

我特地建立了一個僅包含我想重用的代碼的 Types 目錄。想要建立利用次生產代碼的命令行工具,咱們能夠執行如下操做:後端

mkdir -p tools/web-api
cd tools/web-api
swift package init --type executable
複製代碼

如今咱們已經搭建了一個能夠操做的項目。首先讓咱們把生產代碼進行連接:api

cd Sources
ln -s ../../../SymlinkedSPMExample/WebService/Types WebService
cd ..
複製代碼

你要給這個連接使用相對路徑,不然在遷移到別的電腦上時會奔潰bash

如今項目的結構如今看起來像這樣:

.
├── SymlinkedSPMExample
│   ├── AppDelegate.swift
│   ├── Base.lproj
│   │   └── LaunchScreen.storyboard
│   ├── Info.plist
│   ├── ViewController.swift
│   └── WebService
│       ├── Server.swift
│       └── Types
│           ├── BlogPost.swift
│           └── BlogPostsRequest.swift
└── tools
    └── web-api
        ├── Package.swift
        ├── README.md
        ├── Sources
        │   ├── WebServer -> ../../../SymlinkedSPMExample/WebService/Types/
        │   └── web-api
        │       └── main.swift
        └── Tests
複製代碼

如今我須要更新 Package.swift 文件來給代碼建立一個新的 target 而且添加一個依賴,從而使得 web-api 可執行文件能夠使用這些生產代碼

Package.swift

// swift-tools-version:4.0

import PackageDescription

let package = Package(
    name: "web-api",
    targets: [
        .target(name: "web-api", dependencies: [ "WebService" ]),
        .target(name: "WebService"),
    ]
)
複製代碼

既然 SPM 知道如何構建項目,那就讓咱們利用生產解析代碼來寫以前提到的代碼吧。

main.swift

import Foundation
import WebService

do {
  print(try JSONDecoder().decode(BlogPostsRequest.self, from: FileHandle.standardInput.readDataToEndOfFile()).posts)
} catch {
  print(error)
}
複製代碼

有了這些後,咱們如今能夠開始經過這個工具運行 JSON 來看看生產代碼是否會處理它:

如下是咱們嘗試經過這個工具發送有效 JSON 時的樣子:

$ echo '{ "posts" : [] }' | swift run web-api
[]

$ echo '{ "posts" : [ { "title" : "Some post", "tags" : [] } ] }' | swift run web-api
[WebService.BlogPost(title: "Some post", tags: [])]

$ echo '{ "posts" : [ { "title" : "Some post", "tags" : [ { "value" : "cool" } ] } ] }' | swift run web-api
[WebService.BlogPost(title: "Some post", tags: ["cool"])]
複製代碼

下面是當咱們輸入無效的 JSON 時所獲得的錯誤信息示例:

$ echo '{}' | swift run web-api
keyNotFound(CodingKeys(stringValue: "posts", intValue: nil), Swift.DecodingError.Context(codingPath: [], debugDescription: "No value associated with key CodingKeys(stringValue: \"posts\", intValue: nil) (\"posts\").", underlyingError: nil))

$ echo '{ "posts" : [ { } ] }' | swift run web-api
keyNotFound(CodingKeys(stringValue: "title", intValue: nil), Swift.DecodingError.Context(codingPath: [CodingKeys(stringValue: "posts", intValue: nil), _JSONKey(stringValue: "Index 0", intValue: 0)], debugDescription: "No value associated with key CodingKeys(stringValue: \"title\", intValue: nil) (\"title\").", underlyingError: nil))

$ echo '{ "posts" : [ { "title" : "Some post" } ] }' | swift run web-api
keyNotFound(CodingKeys(stringValue: "tags", intValue: nil), Swift.DecodingError.Context(codingPath: [CodingKeys(stringValue: "posts", intValue: nil), _JSONKey(stringValue: "Index 0", intValue: 0)], debugDescription: "No value associated with key CodingKeys(stringValue: \"tags\", intValue: nil) (\"tags\").", underlyingError: nil))
複製代碼
  • 第一個例子是錯誤的,由於它沒有 posts
  • 第二個例子也是錯誤的,由於 posts 沒有 title
  • 第三個例子仍是錯誤的,由於 posts 沒有 tags

在實際應用中,我將用管道的方式輸出一個實時或暫存斷點的 curl 結果,而非手寫的 JSON 代碼。

這真的很酷,由於我能夠看到生產代碼沒有解析其中的一些示例,而且我能夠看到解釋了錯誤緣由的信息。若是沒有這個工具,我須要手動運行應用程序並找出一種方法來獲取不一樣的 JSON 有效負載而來運行解析邏輯。

總結

本文介紹了經過 SPM 使用生產代碼來建立工具的基本技術。你能夠真正地運行它並建立一些漂亮的工做流程,例如:

  • 將該工具添加爲 web-api 的持續集成管道中做爲一個步驟,以確保使移動客戶端崩潰的部署不會發生。
  • 展開該工具以應用業務規則(來自生產代碼)以查看是否在提要,解析或業務規則層級引入了錯誤。

我已經開始在我本身的項目中使用這個想法了,我很高興它能幫助我和我團隊的其餘成員。

若是發現譯文存在錯誤或其餘須要改進的地方,歡迎到 掘金翻譯計劃 對譯文進行修改並 PR,也可得到相應獎勵積分。文章開頭的 本文永久連接 即爲本文在 GitHub 上的 MarkDown 連接。


掘金翻譯計劃 是一個翻譯優質互聯網技術文章的社區,文章來源爲 掘金 上的英文分享文章。內容覆蓋 AndroidiOS前端後端區塊鏈產品設計人工智能等領域,想要查看更多優質譯文請持續關注 掘金翻譯計劃官方微博知乎專欄

相關文章
相關標籤/搜索