欢迎使用 Tagging,这是一个小型库,可以轻松地在 Swift 中创建类型安全的标签。分类对于我们的模型通常非常有用,因此利用编译器确保它们以正确的方式使用,对于使应用程序或系统的模型层更加健壮大有帮助。
这个库强烈受到 JohnSundell/🆔entity 和 mbleigh/acts-as-taggable-on 的启发。有关理论信息,请查看 Swift by Sundell 上的 "Swift 中的类型安全标识符"。
要使用 Tagging,您只需使模型遵循 Taggable
协议,并为其提供一个 tags
属性,如下所示:
struct Article: Taggable {
let tags: [Tag<Article>]
let title: String
}
这样,上面的 Article
标签现在就是类型安全的了! 感谢 Swift 的类型推断能力,也可以通过使用 Tags
作为其类型来实现 Taggable
类型的 tags
:
struct Article: Taggable {
let tags: Tags
let title: String
}
Tags
类型别名会自动为所有 Taggable
类型添加,这使得可以将 [Tag<Article>]
称为 Article.Tags
。
Tag
值默认由字符串支持,但是可以通过给 Taggable
类型一个 RawTag
轻松地进行自定义,但必须至少是 Hashable
:
struct Article: Taggable {
typealias RawTag = UUID
let tags: Tags
let title: String
}
上面的 Article
标签现在由 UUID
而不是 String
支持。
即使 Tagging 专注于类型安全,它仍然提供了几个便利的功能来帮助减少冗长。例如,如果 Tag
由一个可以通过 String
字面量表示的原始值类型支持,那么标签也可以:
let article = Article(tags: ["foo", "bar"], title: "Example")
对于由可以通过 Int
字面量表示的原始值类型支持的标签,情况也是如此:
let article = Article(tags: [7, 9], title: "Example")
当 Tag
的原始值类型符合这些协议之一时,Tag
也变为 Codable
、Hashable
和 Equatable
。
那么 Tagging 究竟是如何使标签更具类型安全的呢? 首先,当使用 Tagging 时,不再可能意外地将一种类型的标签传递给接受另一种类型标签的 API。 例如,以下代码在使用 Tagging 时将无法编译:
articleManager.articles(withTags: user.tags)
上面的编译器会给我们一个错误,因为我们试图将 [Tag<User>]
值传递给一个接受 [Tag<Article>]
的方法 - 与使用纯值(例如 String
或 Int
)作为标签类型相比,这为我们提供了更强的类型安全。
Tagging 还使得不可能意外地声明错误类型的 tags
属性。 因此,以下内容也无法编译:
struct User: Tagging {
let tags: [Tag<Article>]
}
上面的代码将无法编译的原因是 Taggable
要求符合它的类型声明与 conformer 类型相同的标签,再次提供了额外的类型安全级别。
您可以使用以下方法查找最多或最少使用的标签:
taggableCollection.mostUsedTags()
taggableCollection.leastUsedTags()
您还可以通过向该方法传递一个限制来过滤结果,但是默认限制为 20。
taggableCollection.mostUsedTags(10)
taggableCollection.leastUsedTags(10)
或者直接获取原始值。
taggableCollection.mostUsedRawTags()
taggableCollection.leastUsedRawTags()
taggableCollection.tagged(with: "foo")
taggableCollection.tagged(with: ["foo"])
taggableCollection.tagged(with: ["foo", "bar"])
taggableCollection.tagged(with: taggable.tags)
taggableCollection.tagged(with: ["foo", "bar"], match: .all)
taggableCollection.tagged(with: taggable.tags, match: .all)
taggableCollection.tagged(with: ["foo", "bar"], match: .none)
taggableCollection.tagged(with: taggable.tags, match: .none)
由于 Tagging 是在一个 单个文件 中实现的!,最简单的方法就是直接将其拖放到您的 Xcode 项目中。
但是,如果您希望使用依赖项管理器,则可以使用 Swift Package Manager,方法是在您的 Package.swift
文件中将 Tagging 声明为依赖项:
.package(url: "https://github.com/alexruperez/Tagging", from: "0.1.0")
有关更多信息,请参见 Swift Package Manager 文档。
Tagging 是完全公开开发的,非常欢迎您的贡献。
在开始在任何项目中使用 Tagging 之前,强烈建议您花几分钟时间熟悉其文档和内部实现(所有内容都在一个文件中!),这样您就可以准备好解决可能遇到的任何问题或极端情况。
要了解有关用于实现 Tagging 的原理的更多信息,请查看 Swift by Sundell 上的 "Swift 中的类型安全标识符"。
此项目不提供基于 GitHub Issues 的支持,而是鼓励用户积极参与其持续开发 - 通过修复他们遇到的任何错误或改进发现不足的文档。
如果您希望进行更改,请打开一个 Pull Request - 即使它仅包含您计划的更改草案或重现问题的测试 - 然后我们可以从那里进一步讨论它。
希望您喜欢使用 Tagging! 😀