是否可以在Swift中从字符串中在运行时执行代码?

时间:2016-02-15 19:07:45

标签: ios swift closures plist

我有一个与其相关的条件列表。我想将这个项目列表及其条件存储在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文件中。

谢谢!

2 个答案:

答案 0 :(得分:2)

你最接近的是NSPredicate和/或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和Key Values,因此存在一些限制:

  1. 正在评估的对象必须来自NSObject
  2. 属性必须自动翻译为AnyObject,因此我们存储的是int而不是Color。请注意,使用派生属性可能会有所不同。
  3. 替换字典必须为[String:AnyObject],因此您必须使用枚举原始值而不是枚举值本身。

答案 1 :(得分:1)

这听起来像是predicates的工作!

Swift中的函数式编程构造 - mapfilter,速记闭包等 - 是您在命令式代码中表达数据之间关系时的绝佳工具 。但它们并不是解决这些问题的唯一方法。

特别是,能够将数据之间的关系表示为数据通常很有用:

  • 如果您从简单的文件表示中加载一堆数据模型对象,您也可以对它们之间的关系进行编码。

  • 如果您将数据关系编码为数据,则可以在运行时加载/更新/下载它们,而不是更改代码并发送新的应用二进制文件。

  • 如果您正在处理后端数据库/ Web服务/ RDBMS / ORM(CloudKit,核心数据等),您需要一种表达过滤器,查询,排序顺序和关系等方法的方法您可以传递到后端,并在那里进行大型昂贵的数据处理操作。

这是NSPredicate(以及相关的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打败了我。这更像是一个"为什么" /高级答案,但他有一些很好的细节,比如在枚举案例,数据文件内容和谓词格式之间建立映射。