在 Swift 中是否可以在运行时从字符串执行代码?
Is it possible in Swift to execute code at runtime from a string?
我有一个具有相关条件的项目列表。我想将此项目列表及其条件存储在 plist 中,而不是将它们硬编码到 .swift 文件中。
唯一的问题是需要一个与每个项目关联的函数来检查条件。这是硬编码的样子:
let myJobStep1 = JobStep(heading: "My Heading", description: "This is the description", warningText: "", condition_check: { () -> Bool in
return (self.trayColor == .Blue) || (self.trayColor == .Red)
})
let myJobStep2 = JobStep(heading: "My Heading", description: "Another description", warningText: "", condition_check: { () -> Bool in
return (self.trayColor == .Green)
})
问题是如何将检查条件的函数封装在 plist 文件中的字符串中。
谢谢!
你最接近的是 NSPredicate
and/or NSExpression
这给了你动态评估作为字符串给出的表达式的有限能力。
enum Colors : Int {
case Red = 1
case Green = 2
case Blue = 3
}
class Line : NSObject {
var lineColor : Int
init(lineColor:Colors) {
self.lineColor = lineColor.rawValue
}
}
let red = Line(lineColor: .Red)
let green = Line(lineColor: .Green)
let basic = NSPredicate(format: "self.lineColor == $Red")
let test = basic.predicateWithSubstitutionVariables(["Red":Colors.Red.rawValue])
test.evaluateWithObject(red) // true
test.evaluateWithObject(green) // false
由于 NSExpression
基于 Objective-C 和键值,因此存在一些限制:
- 正在评估的对象必须派生自
NSObject
。
- 属性必须自动转换为
AnyObject
,因此我们存储 int 而不是 Color。请注意,您可能会通过使用派生的 属性. 来稍微不同地处理这个问题
- 替换字典必须是
[String:AnyObject]
,因此您必须使用枚举原始值而不是枚举值本身。
这听起来像是 predicates 的工作!
Swift 中的函数式编程构造 — map
、filter
、shorthand 闭包等 — 是表达数据之间关系的绝佳工具命令式代码。但它们并不是看待此类问题的唯一方法。
特别是,能够将数据 之间的关系表示为数据 :
通常很有用
如果您从一个简单的文件表示加载一堆数据模型对象,您也可以这样编码它们的关系。
如果您将数据关系编码为数据,您可以在运行时加载/更新/下载它们,而不是更改代码和发布新的应用程序二进制文件。
如果您正在处理后端数据库/Web 服务/RDBMS/ORM(CloudKit、核心数据等),您需要一种表达过滤器、查询等内容的方法、排序顺序和关系,您可以将它们传递给后端,让昂贵的大数据处理操作在那里发生。
这就是 NSPredicate
(and, relatedly, NSSortDescriptor
) 的用途。与过滤器/比较闭包不同,与谓词相关的基本逻辑可以是数据,而不是代码。因此,您可以拥有如下所示的数据源:
[
"heading": "My Heading",
"description": "This is the description",
"condition": "trayColor == \"Blue\" || trayColor == \"Red\""
]
然后您可以从您的数据源创建谓词:
let predicate = NSPredicate(format: item.condition)
并使用它们来测试单个对象、过滤器集合等的条件:
predicate.evaluateWithObject(item)
(items as NSArray).filteredArrayUsingPredicate(predicate)
编辑: @DavidBerry 先发制人。这更像是一个 "why" / 高级答案,但他有一些很好的详细信息,例如在枚举案例、数据文件内容和谓词格式之间设置映射。
我有一个具有相关条件的项目列表。我想将此项目列表及其条件存储在 plist 中,而不是将它们硬编码到 .swift 文件中。
唯一的问题是需要一个与每个项目关联的函数来检查条件。这是硬编码的样子:
let myJobStep1 = JobStep(heading: "My Heading", description: "This is the description", warningText: "", condition_check: { () -> Bool in
return (self.trayColor == .Blue) || (self.trayColor == .Red)
})
let myJobStep2 = JobStep(heading: "My Heading", description: "Another description", warningText: "", condition_check: { () -> Bool in
return (self.trayColor == .Green)
})
问题是如何将检查条件的函数封装在 plist 文件中的字符串中。
谢谢!
你最接近的是 NSPredicate
and/or NSExpression
这给了你动态评估作为字符串给出的表达式的有限能力。
enum Colors : Int {
case Red = 1
case Green = 2
case Blue = 3
}
class Line : NSObject {
var lineColor : Int
init(lineColor:Colors) {
self.lineColor = lineColor.rawValue
}
}
let red = Line(lineColor: .Red)
let green = Line(lineColor: .Green)
let basic = NSPredicate(format: "self.lineColor == $Red")
let test = basic.predicateWithSubstitutionVariables(["Red":Colors.Red.rawValue])
test.evaluateWithObject(red) // true
test.evaluateWithObject(green) // false
由于 NSExpression
基于 Objective-C 和键值,因此存在一些限制:
- 正在评估的对象必须派生自
NSObject
。 - 属性必须自动转换为
AnyObject
,因此我们存储 int 而不是 Color。请注意,您可能会通过使用派生的 属性. 来稍微不同地处理这个问题
- 替换字典必须是
[String:AnyObject]
,因此您必须使用枚举原始值而不是枚举值本身。
这听起来像是 predicates 的工作!
Swift 中的函数式编程构造 — map
、filter
、shorthand 闭包等 — 是表达数据之间关系的绝佳工具命令式代码。但它们并不是看待此类问题的唯一方法。
特别是,能够将数据 之间的关系表示为数据 :
通常很有用如果您从一个简单的文件表示加载一堆数据模型对象,您也可以这样编码它们的关系。
如果您将数据关系编码为数据,您可以在运行时加载/更新/下载它们,而不是更改代码和发布新的应用程序二进制文件。
如果您正在处理后端数据库/Web 服务/RDBMS/ORM(CloudKit、核心数据等),您需要一种表达过滤器、查询等内容的方法、排序顺序和关系,您可以将它们传递给后端,让昂贵的大数据处理操作在那里发生。
这就是 NSPredicate
(and, relatedly, NSSortDescriptor
) 的用途。与过滤器/比较闭包不同,与谓词相关的基本逻辑可以是数据,而不是代码。因此,您可以拥有如下所示的数据源:
[
"heading": "My Heading",
"description": "This is the description",
"condition": "trayColor == \"Blue\" || trayColor == \"Red\""
]
然后您可以从您的数据源创建谓词:
let predicate = NSPredicate(format: item.condition)
并使用它们来测试单个对象、过滤器集合等的条件:
predicate.evaluateWithObject(item)
(items as NSArray).filteredArrayUsingPredicate(predicate)
编辑: @DavidBerry 先发制人。这更像是一个 "why" / 高级答案,但他有一些很好的详细信息,例如在枚举案例、数据文件内容和谓词格式之间设置映射。