I am trying to get an NSRuleEditor
to display criteria. It works (creates a static label) if I give it a single criterion, but the moment I give it more than one, each row of the rule editor is blank (no subviews are added other than the add/remove buttons). Why would this be? My code is as follows.
struct RuleItem {
var text: String
var children: [RuleItem] = []
}
var ruleItems = [
RuleItem(text: "hello"),
RuleItem(text: "world", children: [
RuleItem(text: "child 1"),
RuleItem(text: "child 2")
])
]
// In class conforming to NSRuleEditorDelegate:
func ruleEditor(_ editor: NSRuleEditor, numberOfChildrenForCriterion criterion: Any?, with rowType: NSRuleEditor.RowType) -> Int {
if let item = criterion as AnyObject as? RuleItem {
return item.children.count
} else {
return ruleItems.count
}
}
func ruleEditor(_ editor: NSRuleEditor, child index: Int, forCriterion criterion: Any?, with rowType: NSRuleEditor.RowType) -> Any {
if let item = criterion as AnyObject as? RuleItem {
return item.children[index]
} else {
return ruleItems[index]
}
}
func ruleEditor(_ editor: NSRuleEditor, displayValueForCriterion criterion: Any, inRow row: Int) -> Any {
(criterion as AnyObject as! RuleItem).text as NSString
}
I solved this myself (after a few frustrating hours).
The problem is that we are returning instances of a Swift structure from the Objective-C protocol method
-ruleEditor:child:forCriterion:withRowType
. These are automatically converted to instances of__SwiftValue
(an Objective-C class) by the compiler. This seems well and good, until we read the following at the top ofNSRuleEditor.h
:So our problem seems to be that the
__SwiftValue
s we're returning don't have a meaningful definition ofisEqual:
. Everything works as expected if we use Objective-C-compatible classes instead of Swift structures.Code that works:
By the way,
NSRuleEditor.h
is leagues more helpful than the actual documentation pages; do yourself a favor and read it through.