Chris Chris - 3 months ago 5
Swift Question

Swift: Enums that use closures?

I’m creating an application where an unlimited amount of rules could be applied to an unlimited amount of nodes.

I'm planning on using core data as the datastore and creating a simple one to many relationship between node and rule.

In objective-c I would probably create classes for each of the rules and have them conform to a protocol.

NSArray *ruleClassNames = @[@"SimpleRuleA",@"SimpleRuleB",@"BigFatComplicatedRule"];

int ruleType = [someNode.rules firstObject];
Class class = NSClassFromString(ruleClassNames[ruleType]);

[(ruleClassProtocol*)class performSelector:@selector(runRuleOnNode:) withObject:someNode];

What would be the most elegant way of doing this in swift?



If we want to add a closure to an enum first of all lets define the type of the closure.

typealias Logic = () -> (String)

Then the enum:

enum Rule {
    case SimpleRuleA(Logic)
    case SimpleRuleB(Logic)
    case BigFatComplicatedRule(Logic)

That's it! Let's see now how to use this.


Let's create a couple of Logic(s):

let logic0 : Logic = { return "Logic 0" }
let logic1 : Logic = { return "Logic 1" }

And now a function to process a Rule

func processRule(rule:Rule) -> String {
    switch rule {
    case .SimpleRuleA(let logic): return "Simple Rule A, logic: \(logic())"
    case .SimpleRuleB(let logic): return "Simple Rule B, logic: \(logic())"
    case .BigFatComplicatedRule(let logic): return "Big Fat Complicated Rule, logic: \(logic())"

Finally let's combine every possible rule with every possible Logic...

let aWithLogic0 = Rule.SimpleRuleA(logic0)
let aWithLogic1 = Rule.SimpleRuleA(logic1)
let bWithLogic0 = Rule.SimpleRuleB(logic0)
let bWithLogic1 = Rule.SimpleRuleB(logic1)
let fatWithLogic0 = Rule.BigFatComplicatedRule(logic0)
let fatWithLogic1 = Rule.BigFatComplicatedRule(logic1)

... and let's test it

processRule(aWithLogic0) // "Simple Rule A, logic: Logic 0"
processRule(aWithLogic1) // "Simple Rule A, logic: Logic 1"
processRule(bWithLogic0) // "Simple Rule B, logic: Logic 0"
processRule(bWithLogic1) // "Simple Rule B, logic: Logic 1"
processRule(fatWithLogic0) // "Big Fat Complicated Rule, logic: Logic 0"
processRule(fatWithLogic1) // "Big Fat Complicated Rule, logic: Logic 1"

Is this solution close to what you had in mind?