开发工具代码生成【免费下载链接】SwiftGenThe Swift code generator for your assets, storyboards, Localizable.strings, … — Get rid of all String-based APIs!项目地址https://gitcode.com/gh_mirrors/sw/SwiftGen点击查看免费下载本文以 SwiftGen 内置的plist/runtime-swift5.stencil模板为主线讲解如何让生成代码在运行时从 Bundle 中加载 Plist 文件并据此产出类型安全的 Swift 5 常量。你将掌握该模板的适用场景、全部可定制参数bundle、enumName、forceFileNameEnum、lookupFunction、preservePath、publicAccess的用法与底层实现原理并学会通过配置文件将其接入 Xcode 项目。模板概览runtime-swift5是 SwiftGen 为 Plist 解析器提供的两种内置模板之一另一套为inline-swift5。与 inline 模板把 Plist 数据直接内联进生成的 Swift 源码不同runtime 模板生成的代码在运行时通过Bundle.url(forResource:withExtension:)或自定义查找函数定位并读取 Plist 文件再以强类型常量暴露其中的数据。属性值模板文件plist/runtime-swift5.stencil目标语言Swift 5作者David Jennes模板源文件位于 Sources/SwiftGenCLI/templates/plist/runtime-swift5.stencil同一套实现还有面向 Swift 4 的runtime-swift4.stencil两者逻辑完全一致。在 SwiftGen 配置文件中这样引用它plist: inputs: path/to/plist/dir-or-file outputs: templateName: runtime-swift5 output: Plist.swift关于配置文件各键inputs、outputs、templateName、params等的完整说明参见 配置文件文档其中params正是下文所有定制参数的入口。何时使用该模板runtime-swift5适合以下场景需要生成Swift 5代码希望在运行时从当前 Bundle 加载 Plist 文件而不是把数据编译进代码里从而支持数据在应用包内随版本更新、或在多个 target 间共享你的 Plist 结构在编译期已知、且希望获得强类型常量访问。如果需求超出该模板的能力——例如从Documents目录加载文件、处理Optional属性等——则建议参考 创建自定义模板指南 编写自己的 Stencil 模板。与 inline 模板相比runtime 模板的取舍很清晰inline 版本直接嵌入数据、无运行时查找开销但数据变更必须重新生成代码runtime 版本则在运行时读取适合数据与代码解耦的场景。两种模板生成的对外 API 形态完全一致因此切换模板通常不影响调用方代码。自定义参数详解运行swiftgen时可通过params覆盖以下参数定制生成结果。所有参数均为可选。参数名默认值作用bundleBundleToken.bundle指定从哪个 Bundle 加载 Plist 文件。默认指向生成代码所在的那个 Bundle。注意设置lookupFunction后本参数会被忽略。enumNamePlistFiles修改承载所有文件常量的外层enum名称。forceFileNameEnum无设置后即使输入只有一个 Plist 文件也会生成enum FileName这一层嵌套。lookupFunction无¹指定自定义查找函数签名为(path: String) - URL?。参数名可任意甚至无外部参数名但若函数带具名参数必须提供完整签名如myPlistFinder(path:)。设置后bundle参数被忽略。preservePath无关闭对文件路径的 basename 过滤。当你在 Xcode 项目中以「folder reference」蓝色文件夹方式添加数据目录、希望保留目录层级时使用路径将相对于你交给 SwiftGen 的目录。publicAccess无设置后生成的常量标记为public否则为internal。¹ 若不提供lookupFunction模板会退化为对bundle参数调用url(forResource:withExtension:)。参数在模板中的落地位置这些参数并非黑盒开关而是直接体现在模板源码的不同分支中见 runtime-swift5.stencil访问级别模板第 5 行通过{% if param.publicAccess %}public{% else %}internal{% endif %}决定accessModifier该变量贯穿所有生成的 enum 与常量声明外层 enum 名第 51 行{{param.enumName|default:PlistFiles}}使用 Stencil 的default过滤器未设置时回退到PlistFiles文件名枚举第 52 行{% if files.count 1 or param.forceFileNameEnum %}判断——只有一个文件且未设置forceFileNameEnum时文件内容会被直接展开进外层 enum对应文档中PlistFiles.Configuration直接嵌套的示例多文件或设置该参数时才包一层enum FileName路径处理第 4248 行的transformPath宏根据preservePath决定使用完整相对路径还是basename过滤后的文件名查找逻辑第 6676 行与 8190 行lookupFunction优先于bundle生效二者择一生成 URL 获取代码BundleToken第 100113 行仅当bundle与lookupFunction都未设置时才生成BundleToken辅助类其内部通过#if SWIFT_PACKAGE区分 Swift Package 与普通 App target分别返回Bundle.module或Bundle(for: BundleToken.self)。测试套件 Tests/TemplatesTests/PlistTests.swift 中的runtimeVariations完整覆盖了上述 7 种参数组合customBundle、customName、forceFileNameEnum、lookupFunction、preservePath、publicAccess及默认形态生成结果与 Sources/TestUtils/Fixtures/Generated/Plist/runtime-swift5 目录下的 fixture 一一对应是验证参数行为的现成参考。配置示例结合 params 使用plist: inputs: Resources/Plist outputs: templateName: runtime-swift5 output: Generated/Plist.swift params: enumName: AppPlist publicAccess: true forceFileNameEnum: true注意配置文件中所有相对路径均以配置文件自身所在目录为基准见 ConfigFile.md。outputs支持数组形式可对同一批输入同时生成多份输出例如同时产出 runtime 与 inline 两种风格输入只会被解析一次。生成代码解读代码片段以下是文档给出的生成代码示例internal enum PlistFiles { internal enum Configuration { private static let _document PlistDocument(path: configuration.plist) internal static let environment: String _document[Environment] internal static let options: [String: Any] _document[Options] } internal enum ShoppingList { internal static let items: [String] arrayFromPlist(at: shopping-list.plist) } }完整生成结果可查看 Sources/TestUtils/Fixtures/Generated/Plist/runtime-swift5/all.swift——该 fixture 由all.yaml上下文渲染而来覆盖Info.plist含 23 个属性、configuration.plist含数组、字典、布尔、日期等混合类型与shopping-list.plist纯字符串数组三个文件。两种根类型的处理分支观察生成代码可以发现模板对 Plist 的根节点类型分情况处理对应模板第 1726 行根节点是 Dictionary生成private static let _document PlistDocument(path: ...)随后为每个键生成一个static let 属性名: 类型 _document[键]根节点是 Array直接生成static let items: [元素类型] arrayFromPlist(at: ...)其他根类型仅输出// Unsupported root type注释不生成常量。类型推断机制生成的属性类型来自 SwiftGenKit 对 Plist 内容的元数据推断。解析阶段PlistFile.swift 使用PropertyListDecoderAnyCodable解码文件内容并在 Stencil 上下文构建时PlistParserContext.swift通过Metadata.generate(for:)递归描述每个值的类型。类型映射逻辑集中在 Sources/SwiftGenKit/Utils/Metadata.swiftString、Bool、Int、Double、Date、Data分别映射为同名 Swift 类型字典映射为[String: Any]数组映射为[元素类型]如[String]、[Bool]、[Int]数字类型通过 CoreFoundation 的CFNumberGetType区分整型与浮点第 117131 行对NSNumber数组还会逐元素检查类型一致性第 140148 行只有全部元素类型一致时才给出确定元素类型否则回退为[Any]——这解释了为何all.swift中会出现mixed: [Any]这类保守推断。运行时加载的实现细节模板文件第 64 行之后是生成的「Implementation Details」段包含两个关键组件arrayFromPlistT(at:)通过NSArray(contentsOf: url)读取数组型 Plist 并尝试转换为[T]失败则fatalErrorPlistDocument一个轻量 structinit中通过NSDictionary(contentsOf: url)读取字典型 Plist并提供subscriptT(key:)按类型取出属性值类型不匹配时同样fatalError。两者都依赖Bundle.url(forResource:withExtension:)或lookupFunction先拿到文件 URL。因此运行时加载失败如资源未打进 Bundle会在访问常量时直接触发崩溃这是 runtime 模板与 inline 模板最大的行为差异——inline 版本数据已编译进代码不存在此问题。使用示例// 这是一个数组 let foo PlistFiles.ShoppingList.items // 这是一个 String let bar PlistFiles.Configuration.environment调用方式与 inline 模板完全一致迁移模板时无需修改调用方代码。更完整的用法可参考 SwiftGen.playground 中的 Plist 演示页。与底层解析器的配合runtime-swift5只负责渲染数据解析由 SwiftGenKit 的 Plist 解析器完成。解析器入口在 PlistParser.swift默认过滤器为.plist扩展名defaultFilter它接受多个文件或目录目录会递归扫描每个文件的name去扩展名文件名、path相对路径以及解码后的document内容都会进入 Stencil 上下文。该上下文结构与 JSON、YAML 解析器保持一致见 SwiftGenKit Contexts/plist.md因此你可以在 JSON、Plist、YAML 三类输入之间无缝切换同一套模板。结语plist/runtime-swift5是「运行时加载 编译期类型安全」两种诉求的折中方案它把数据读取延迟到运行时同时借助 SwiftGenKit 的元数据推断为每个属性生成确定类型。理解bundle/lookupFunction的资源查找链路、preservePath对路径的影响以及 Dictionary/Array 两种根类型的分支逻辑就能在 Xcode 项目、Swift Package 与自定义资源目录等不同布局下正确驾驭该模板。赞分享开发工具代码生成【免费下载链接】SwiftGenThe Swift code generator for your assets, storyboards, Localizable.strings, … — Get rid of all String-based APIs!项目地址https://gitcode.com/gh_mirrors/sw/SwiftGen点击查看免费下载相关推荐SwiftGen Plist runtime-swift4 模板深度指南运行时加载 Plist 的类型安全代码生成SwiftGen Plist runtime swift4 模板深度指南运行时加载 Plist 的类型安全代码生成 导读 本文以 SwiftGen 仓库中的开发工具代码生成SwiftGen Plist 模板指南inline-swift5 内联生成 Plist 常量代码SwiftGen Plist 模板指南inline swift5 内联生成 Plist 常量代码 本文聚焦 SwiftGen 仓库中随附的 plist/inl开发工具代码生成SwiftGen JSON runtime-swift5 模板完全指南在运行时从 Bundle 加载 JSON 数据的类型安全方案SwiftGen JSON runtime swift5 模板完全指南在运行时从 Bundle 加载 JSON 数据的类型安全方案 本文是 SwiftGen开发工具代码生成上一篇Security-101 课程精讲IAM 身份与访问管理核心概念最小特权、职责分离与认证授权下一篇骑马与砍杀2多人联机完整教程BannerlordCoop模组从安装到开服的快速配置指南创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
