SwiftGen 6.6.3

SwiftGen 6.6.3

测试已测试
Lang语言 Obj-CObjective C
许可证 MIT
发布最后发布2024年3月

Olivier HalligonDavid Jennes 维护。



SwiftGen 6.6.3

  • Olivier Halligon 和 David Jennes

CircleCI

SwiftGen 是一个工具,用于为项目的资源自动生成 Swift 代码,以使它们在使用时类型安全。

SwiftGen Logo 然后为以下内容生成代码(枚举、常量等)

使用此工具有许多好处

  • 避免在使用字符串时出现任何错误
  • 免费的自动完成
  • 避免使用不存在的资产名称的风险
  • 所有这些都将通过编译器得到保证。

此外,由于 Stencil 模板,它完全可以自定义,因此即使它提供了预定义的模板,您也可以创建自己以生成符合您需求和指南的任何代码!

安装

根据您的偏好和需求,有多种方法可以在您的计算机或项目中安装 SwiftGen

下载 ZIP 文件 以获取最新版本

我们建议您在项目目录中 解压缩 ZIP提交其内容 到 git。这样,所有同事将为该项目使用 SwiftGen 的相同版本

如果您在项目目录根目录下解压缩了 ZIP 文件到名为 swiftgen 的文件夹中,则可以在脚本构建阶段使用以下代码调用 SwiftGen

"$PROJECT_DIR"/swiftgen/bin/swiftgen …

通过 CocoaPods

如果您正在使用 CocoaPods,则可以将 pod 'SwiftGen' 添加到您的 Podfile

这将在您下一次执行 pod install 时在 Pods/ 中下载 SwiftGen 二进制文件及其依赖项。

由于您可以在 Podfile 中指定 SwiftGen 的确切版本,这允许您确保 所有同事将为该项目使用 SwiftGen 的相同版本

然后您可以在脚本构建阶段使用以下方式调用 SwiftGen

$PODS_ROOT/SwiftGen/bin/swiftgen …

注意:SwiftGen 并不是真正的 pod,因为它不是您的代码在运行时依赖的库;因此,通过 CocoaPods 的安装只是将 SwiftGen 二进制文件安装到 Pods/ 文件夹中的小花招,但您不会在 Xcode 的 Pods.xcodeproj 中的 Pods/SwiftGen 组中看到任何 swift 文件。这是正常的:SwiftGen 二进制文件仍然在该文件夹的 Finder 中。


通过 Homebrew (系统级安装)

要通过 Homebrew 安装 SwiftGen,只需使用以下命令

$ brew update
$ brew install swiftgen

这将全局安装SwiftGen 系统级。该机器上的所有项目都将使用同一版本的SwiftGen,并且你应该确保所有同事在他们的机器上也安装了相同版本的SwiftGen。

然后你可以在脚本的构建阶段直接调用swiftgen(因为它已经存在于你的$PATH中了)

swiftgen … 

注意:SwiftGen需要Xcode 8.3来编译,因此通过Homebrew安装需要你已经安装了Xcode 8.3(这反过来又需要macOS 10.12)。如果你使用的是更早版本的macOS,你必须使用其他安装方法之一。


从源码编译 (仅建议在需要master分支特有的功能或想要测试PR时使用)

这种解决方案是当你想要从master中构建和安装最新版本,并访问可能还未发布的功能时。

  • 如果你已经安装了homebrew,你可以使用以下命令来构建和安装最新的提交
brew install swiftgen --HEAD
  • 或者,你可以克隆存储库,并使用rake cli:install来构建工具并从任何分支安装它,这对于在分叉或PR分支中测试SwiftGen很有用。

你可以安装到默认位置(无需参数)或自定义位置

# Binary is installed in `./swiftgen/bin`, frameworks in `./swiftgen/lib` and templates in `./swiftgen/templates`
$ rake cli:install
# - OR -
# Binary will be installed in `~/swiftgen/bin`, frameworks in `~/swiftgen/fmk` and templates in `~/swiftgen/tpl`
$ rake cli:install[~/swiftgen/bin,~/swiftgen/fmk,~/swiftgen/tpl]

然后你可以通过你安装 SwiftGen 的二进制文件路径调用 SwiftGen

~/swiftgen/bin/swiftgen …

或者,将 bin 文件的路径添加到你的 $PATH 中并直接调用 swiftgen


用法

❗️如果你从SwiftGen 4.x迁移到SwiftGen 5.x,不要忘记阅读迁移指南

工具提供了一个独特的swiftgen二进制命令行,并提供了以下子命令来解析不同的资源类型

  • swiftgen colors [选项] FILE1 …
  • swiftgen fonts [选项] DIR1 …
  • swiftgen storyboards [选项] DIR1 …
  • swiftgen strings [选项] FILE1 …
  • swiftgen xcassets [选项] CATALOG1 …

每个子命令都有自己的选项和语法,但某些选项对所有子命令都是通用的

  • --output FILE-o FILE:设置要写入生成代码的文件。如果省略,则生成的代码将打印在stdout上。
  • --template NAME-t NAME:定义要使用的Stencil模板的名称(按照名称,请参阅这里了解更多信息)以生成输出。
  • --templatePath PATH-p PATH:定义要使用的Stencil模板,使用完整路径。
  • 注意:调用SwiftGen时,你应该指定一个模板。你必须使用-t-p,但不能同时使用两者(这样做也没有意义,并且如果你尝试这样做,你会得到错误)
  • 每个命令都支持多个输入文件(或适用于目录的情况)。

还有其他与生成代码无关的子命令,更多地是面向帮助和配置,如下所述

  • swiftgen templates子命令帮助你打印、复制、查找和管理模板(包括打包和自定义)
  • swiftgen config子命令帮助你管理配置文件(详见下文)
  • 您可以通过在swiftgen或其子命令上使用--help来查看详细的用法。

使用配置文件

与其为每种需要生成代码的资源类型手动调用SwiftGen,并为每次调用提供正确的参数列表,不如使用配置文件更简单。

只需创建一个swiftgen.yml YAML文件,列出要调用的所有子命令,并针对每个子命令列出要传递给它的参数列表。例如

strings:
  paths: Resources/Base.lproj/Localizable.strings
  templateName: structured-swift3
  output: Generated/strings.swift
xcassets:
  paths:
   - Resources/Images.xcassets
   - Resources/MoreImages.xcassets
  templateName: swift3
  output: Generated/assets-images.swift

然后您只需要调用 swiftgen config run 命令,或者更简短的 swiftgen 命令,它将执行配置文件中描述的内容。

要了解更多关于配置文件的信息——其更详细的语法和可能性,如何传递自定义参数,如何使用 swiftgen config lint 验证它,如何使用备用配置文件以及其他提示——请参阅专门的文档:点击这里

选择你的模板

SwiftGen 基于模板(它使用 Stencil 作为其模板引擎)。这意味着您可以选择适合您使用的 Swift 版本的模板——以及最适合您喜好的模板——以将生成的代码适配到您自己的约定和 Swift 版本。

内置模板与自定义模板

SwiftGen 为每个子命令(colorsfontsstoryboardsstringsxcassets)定义了一些内置模板,这些模板适用于大多数需求。但是,如果您觉得内置模板不符合您的编程约定或需求,您也可以创建自己的模板。只需使用 -t / --template 选项指定要使用的模板名称,或者在您的项目存储库中存放在其他位置,并使用 -p / --templatePath 指定完整路径。

💡您可以使用 swiftgen templates list 命令列出每个子命令的所有可用模板(包括自定义模板和内置模板),查看模板内容,并复制它们来创建自己的模板。

有关创建自己的模板的更多信息,请参阅专门的文档:点击这里

SwiftGen 内置的模板

如上所述,您可以使用 swiftgen templates list 列出 SwiftGen 所捆绑的所有模板。对于大多数 SwiftGen 子命令,我们提供,其中之一

  • swift2 模板,兼容 Swift 2版
  • swift3 模板,兼容 Swift 3版
  • swift4 模板,兼容 Swift 4版
  • 其他变体,如字符串等 flat-swift2/3/4structured-swift2/3/4 模板。

您可以在 此处 找到每个内置模板的文档,文档按照每个 SwiftGen 子命令一个文件夹,每个模板一个 Markdown 文件来组织。
每个 Markdown 文件都记录了其目标 Swift 版本,该模板的使用场景(在哪些情况下您可能更喜欢该模板而不是其他模板),在调用时可以根据需要自定义的 --param 参数,以及一些代码示例。

请毫不犹豫地提交 PR,分享您对内置模板的改进建议😉

附加文档

Playground

此存储库中可用的 SwiftGen.playground 允许您与该工具通常生成的代码互动,并查看一些示例,说明您可以如何充分利用它。

这使您能够快速查看 SwiftGen 生成的典型代码的外观,以及您将如何在此代码中使用生成的常量。

Markdown 文件

此外,此存储库和相关的 SwiftGenKit/StencilSwiftKit/templates 存储库中还有大量以 Markdown 文件形式存在的文档。请确保检查每个存储库中的 "Documentation" 文件夹。

Wiki

您还可以在 Wiki 中看到一些额外的文档,包括有关

教程

您还可以在网上找到其他帮助和教程材料,如我在 2017 年 9 月在 FrenchKit 上提供的关于代码生成的课堂这里 —— 以及其 Wiki,它详细说明了如何安装和使用 SwiftGen(以及 Sourcery)的逐步教程。


资产目录

swiftgen xcassets -t swift3 /dir/to/search/for/imageset/assets

这将生成一个enum Asset,每个图像集在你的资产目录中有相应的case,这样你就可以把它们用作常量。

由捆绑模板生成的代码示例
enum Asset {
  enum Exotic {
    static let banana: AssetType = "Exotic/Banana"
    static let mango: AssetType = "Exotic/Mango"
  }
  static let `private`: AssetType = "private"
}

使用示例

// You can create new images with the convenience constructor like this:
let bananaImage = UIImage(asset: Asset.Exotic.banana)  // iOS
let privateImage = NSImage(asset: Asset.private)  // macOS

// Or as an alternative, you can refer to enum instance and call .image on it:
let sameBananaImage = Asset.Exotic.banana.image
let samePrivateImage = Asset.private.image

颜色

swiftgen colors -t swift3 /path/to/colors-file.txt

这将生成一个enum ColorName,每个通过参数传入的文本文件中列出的颜色对应一个case

输入文件应该是以下之一:

  • 一个
  • 一个
  • 一个
  • 一个由苹果的Color Palettes使用的

例如,你可以使用这个命令来从一个系统颜色列表生成颜色

swiftgen colors -swift3 ~/Library/Colors/MyColors.clr

生成的代码将看起来像使用文本文件一样。

由捆绑模板生成的代码示例

给定以下

Cyan-Color       : 0xff66ccff
ArticleTitle     : #33fe66
ArticleBody      : 339666
ArticleFootnote  : ff66ccff
Translucent      : ffffffcc

生成的代码将看起来像这样

struct ColorName {
  let rgbaValue: UInt32
  var color: Color { return Color(named: self) }

  /// <span style="display:block;width:3em;height:2em;border:1px solid black;background:#339666"></span>
  /// Alpha: 100% <br/> (0x339666ff)
  static let articleBody = ColorName(rgbaValue: 0x339666ff)
  /// <span style="display:block;width:3em;height:2em;border:1px solid black;background:#ff66cc"></span>
  /// Alpha: 100% <br/> (0xff66ccff)
  static let articleFootnote = ColorName(rgbaValue: 0xff66ccff)

  ...
}

使用示例

// You can create colors with the convenience constructor like this:
let title = UIColor(named: .articleBody)  // iOS
let footnote = NSColor(named: .articleFootnote) // macOS

// Or as an alternative, you can refer to enum instance and call .color on it:
let sameTitle = ColorName.articleBody.color
let sameFootnote = ColorName.articleFootnote.color

这样,你无需每次输入红色、绿色、蓝色、alpha值,并为它们在全局命名空间中创建丑陋的常量。

字体

swiftgen fonts -t swift3 /path/to/font/dir

这将递归遍历指定的目录,找到任何字体文件(TTF、OTF等),为每个字体族定义一个struct FontFamily,以及在该家族内部嵌套一个枚举表示这些字体样式。

由捆绑模板生成的代码示例
enum FontFamily {
  enum SFNSDisplay: String, FontConvertible {
    static let regular = FontConvertible(name: ".SFNSDisplay-Regular", family: ".SF NS Display", path: "SFNSDisplay-Regular.otf")
  }
  enum ZapfDingbats: String, FontConvertible {
    static let regular = FontConvertible(name: "ZapfDingbatsITC", family: "Zapf Dingbats", path: "ZapfDingbats.ttf")
  }
}

用法

// You can create fonts with the convenience constructor like this:
let displayRegular = UIFont(font: FontFamily.SFNSDisplay.regular, size: 20.0) // iOS
let dingbats = NSFont(font: FontFamily.ZapfDingbats.regular, size: 20.0)  // macOS

// Or as an alternative, you can refer to enum instance and call .font on it:
let sameDisplayRegular = FontFamily.SFNSDisplay.regular.font(size: 20.0)
let sameDingbats = FontFamily.ZapfDingbats.regular.font(size: 20.0)

故事板

swiftgen storyboards -t swift3 /dir/to/search/for/storyboards

这将为每个NSStoryboard/UIStoryboard生成一个枚举,每个场景对应一个case

由捆绑模板生成的代码示例

生成的代码将看起来像这样

enum StoryboardScene {
  enum Dependency: StoryboardType {
    static let storyboardName = "Dependency"

    static let dependent = SceneType<UIViewController>(storyboard: Dependency.self, identifier: "Dependent")
  }
  enum Message: StoryboardType {
    static let storyboardName = "Message"

    static let messagesList = SceneType<UITableViewController>(storyboard: Message.self, identifier: "MessagesList")
  }
}

enum StoryboardSegue {
  enum Message: String, SegueType {
    case embed
    case nonCustom
  }
}

使用示例

// You can instantiate scenes using the `instantiate` method:
let vc = StoryboardScene.Dependency.dependent.instantiate()

// You can perform segues using:
vc.perform(segue: StoryboardSegue.Message.embed)

// or match them (in prepareForSegue):
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
  switch StoryboardSegue.Message(rawValue: segue.identifier!)! {
  case .embed:
    // Prepare for your custom segue transition
  case .nonCustom:
    // Pass in information to the destination View Controller
  }
}

字符串

swiftgen strings -t structured-swift3 /path/to/Localizable.strings

这将生成一个Swift enum L10n,将所有Localizable.strings(或其它表格)的关键字映射到一个enum case。另外,如果它检测到类似于%@%d%f的占位符,它将为该case添加关联值。请注意,关键字中的所有点都转换为代码中的点号。

由结构化捆绑模板生成的代码示例

给定以下

"alert_title" = "Title of the alert";
"alert_message" = "Some alert body there";
"apples.count" = "You have %d apples";
"bananas.owner" = "Those %d bananas belong to %@.";

提醒:不要忘记在您的 😉

生成的代码将包含以下内容

enum L10n {
  /// Some alert body there
  static let alertMessage = L10n.tr("alert_message")
  /// Title of the alert
  static let alertTitle = L10n.tr("alert_title")

  enum Apples {
    /// You have %d apples
    static func count(_ p1: Int) -> String {
      return L10n.tr("apples.count", p1)
    }
  }

  enum Bananas {
    /// Those %d bananas belong to %@.
    static func owner(_ p1: Int, _ p2: String) -> String {
      return L10n.tr("bananas.owner", p1, p2)
    }
  }
}

使用示例

一旦脚本生成代码,您可以在Swift代码中以这种方式使用它

// Simple strings
let message = L10n.alertMessage
let title = L10n.alertTitle

// with parameters, note that each argument needs to be of the correct type
let apples = L10n.Apples.count(3)
let bananas = L10n.Bananas.owner(5, "Olivier")

支持平坦字符串

SwiftGen还有支持平坦字符串文件(即无点语法)的模板。优点是你的键不会被以任何方式混淆,缺点是自动补全的性能更差。

由平坦捆绑模板生成的代码示例
enum L10n {
  /// Some alert body there
  case alertMessage
  /// Title of the alert
  case alertTitle
  /// You have %d apples
  case applesCount(Int)
  /// Those %d bananas belong to %@.
  case bananasOwner(Int, String)
}

给定与上面相同的

// Simple strings
let message = L10n.alertMessage
let title = L10n.alertTitle

// with parameters, note that each argument needs to be of the correct type
let apples = L10n.applesCount(3)
let bananas = L10n.bananasOwner(5, "Olivier")

许可证

此代码和工具受MIT许可证的许可。请参阅此存储库中的

归属

此工具由以下提供支持

主要由 🎉

如果你想贡献,不要犹豫,请开设一个[Pull Request](#)或甚至加入我们的团队!

其他库/工具

如果你不仅想为你的资源,而且还想为UITableViewCellUICollectionViewCell和XIB视图摆脱基于String的API,你应该看看我的Mixin Reusable

如果你想从你的Swift代码生成Swift代码(所以元啊!),例如为你的类型生成Equatable约定以及许多其他类似的事情,请使用Sourcery

SwiftGen和Sourcery是互补的工具。实际上,Sourcery也使用了Stencil,以及SwiftGen的StencilSwiftKit,因此你可以使用完全相同的语法为两者编写模板!

你也可以通过Twitter关注我,获取其他项目的最新消息或更新,或者阅读我的博客