反复做同样的事情,却期待不同的结果。
Swift 是一种美丽的语言,为许多优秀的 iOS 应用提供了动力。不幸的是,它具有非常有限的运行时和没有元编程功能。这导致我们的项目中充满了大量的重复代码模式,可以认为是相同的代码,只是进行了最小的修改。
你有没有?
如果您这样做,您可能发现自己在编写大量重复的代码来处理这些场景,这感觉对吗?
更糟糕的是,如果您为类型添加了新的属性,所有这些实现都必须更新,否则您将陷入 bug 的境地。在这些场景中,通常 编译器不会生成错误信息供您处理,这使得代码易于出错。
Insanity 是一种工具,它可以扫描您的源代码,应用您个人的模板,并为您生成 Swift 代码,让您可以使用元编程技术来节省时间并减少潜在错误。
使用 Insanity 方法有多种好处
守护模式运行效果
所有事物是如何连接的
+--------------+
Scans code to build AST | | Generates new code
+----------------------------> INSANITY +--------------------------------+
| | | |
| +--^--------^--+ |
| | | |
| | | Reads templates |
| | | |
+-----+------+ +----------------+--+ +--+----------------+ +---------v---------+
| | | | | | | |
| Source | | Equality Template | | NSCoding Template | | Generated Swift |
| | | | | | | |
+-----^------+ +-------------------+ +-------------------+ +-------------------+
| |
| |
| |
+----------------------------------------------------------------------------+
Compiled into your project
我想知道每个枚举中有多少元素
模板
{% for enum in types.enums %}
extension {{ enum.name }} {
static var count: Int { return {{ enum.cases.count }} }
}
{% endfor %}
结果
extension AdType {
static var count: Int { return 2 }
}
模板
{% for type in types.implementing.AutoEquatable %}
extension {{ type.name }}: Equatable {}
func == (lhs: {{ type.name }}, rhs: {{ type.name }}) -> Bool {
{% for variable in type.storedVariables %} if lhs.{{ variable.name }} != rhs.{{ variable.name }} { return false }
{% endfor %}
return true
}
{% endfor %}
结果
extension AccountSectionConfiguration: Equatable {}
func == (lhs: AccountSectionConfiguration, rhs: AccountSectionConfiguration) -> Bool {
if lhs.status != rhs.status { return false }
if lhs.user != rhs.user { return false }
if lhs.entitlements != rhs.entitlements { return false }
return true
}
模板
{% for variable in type.VideoViewModel.computedVariables %} {{ variable.name }}: {{ variable.type }}
{% endfor %}
结果
attributedTitle: NSAttributedString
attributedKicker: NSAttributedString
attributedHeadline: NSAttributedString
attributedSummary: NSAttributedString
Insanity 模板由 Stencil 提供
确保您利用 Insanity 内置守护进程来使编写模板变得更加愉快:您可以打开模板并与生成的代码并排显示,并实时查看其变化。
有多个方法来访问您的类型
type.TypeName
=>通过名称访问特定类型types.all
=>所有类型(排除协议)types.classes
types.structs
types.enums
types.protocols
=>列出所有协议(在项目中定义的协议)types.inheriting.BaseClassOrProtocol
=>列出所有从给定基类继承或实现给定协议的类型types.implementing.BaseClassOrProtocol
=>与 .inheriting
功能完全相同的便捷别称对于每种类型,您可以访问以下属性
name
localName
<-父作用域中的名称staticVariables
<-静态变量列表variables
<-实例变量列表computedVariables
<-计算实例变量列表storedVariables
<-计算存储变量列表inheritedTypes
<-实施/继承此类型的类型名称列表containedTypes
<-在此类型中包含的类型列表parentName
<-包含类型的父类型列表Enum 类型建立在常规类型之上,并添加
rawType
<-枚举原始类型cases
<-Enum.Case
列表Enum.Case 提供
name
<-名称rawValue
<-原始值associatedValues
<-AssociatedValue
列表Enum.Case.AssociatedValue 提供
name
<-名称type
<-相关值的类型这将下载 Insanity 可执行文件和依赖项到 Pods/
。您只需要将 $PODS_ROOT/Insanity/bin/Insanity
添加到您的 Script Build Phases。
Insanity.xcworkspace
。Insanity 是一个命令行工具 Insanity
$ ./Insanity <source> <templates> <output>
参数
选项
--watch
[默认:false] - 监视模板的变化,并根据需要重新生成。仅适用于特定模板路径(不是目录)。--verbose
[默认:false] - 启用忽略实体的详细日志记录欢迎并向 Insanity 贡献!
请参阅 贡献指南。
为了使社区期望清晰,Insanity 采用了贡献者誓言中定义的行为准则。这份文件在许多开源社区中使用,我认为它很好地阐述了我们的价值观。更多信息,请参阅 行为准则。
Insanity遵循MIT许可协议。更多信息请见LICENSE。
本工具由以下组件支持
Olivier Halligon指给我一些他的CLI工具设置脚本,非常实用,谢谢!
如果您想生成与资产相关的逻辑代码,我强烈推荐SwiftGen
请确保检查我的其他库和工具,尤其是
您可以在Twitter上关注我的项目更新。