NSOutlineView crashes when using the isGroupItem delegate method with Swift

I want to expand the list of sources using NSOutlineView in a Swift project.

The view controller below works well when the delegate method of isGroupItem is not called. However, many __NSMallocBlock__ elements will be returned using the isGroupItem method. Which I have no idea where these items come from. The elements I provided are just strings.

class ViewController: NSViewController, NSOutlineViewDataSource, NSOutlineViewDelegate { let topLevel = ["1", "2"] let secLevel = ["1": ["1.1", "1.2"], "2": ["2.1", "2.2"]] func outlineView(outlineView: NSOutlineView, numberOfChildrenOfItem item: AnyObject?) -> Int { if let str = item as? String { let arr = secLevel[str]! as [String] return arr.count } else { return topLevel.count } } func outlineView(outlineView: NSOutlineView, isItemExpandable item: AnyObject) -> Bool { return outlineView.parentForItem(item) == nil } func outlineView(outlineView: NSOutlineView, child index: Int, ofItem item: AnyObject?) -> AnyObject { var output: String! if let str = item as? String { output = secLevel[str]![index] } else { output = topLevel[index] } return NSString(string: output) } func outlineView(outlineView: NSOutlineView, objectValueForTableColumn tableColumn: NSTableColumn?, byItem item: AnyObject?) -> AnyObject? { return item } func outlineView(outlineView: NSOutlineView, isGroupItem item: AnyObject) -> Bool { return (outlineView.parentForItem(item) == nil) } func outlineView(outlineView: NSOutlineView, viewForTableColumn tableColumn: NSTableColumn?, item: AnyObject) -> NSView? { return outlineView.makeViewWithIdentifier("HeaderCell", owner: self) as NSTextField } } 

A sample project can be downloaded here.

+7
cocoa swift nsoutlineview
source share
3 answers

This question was answered by Ken Thomases at the Apple Developer Forum. What he said is extracted here:

Elements that you specify as a path must be constant. In addition, you must return the same element every time for a given parent and index. You cannot return objects that were created ad hoc, for example, you do in -outlineView: child: ofItem: where you call the NSString convenience constructor.

It works fine after saving data source objects as follows:

 let topLevel = [NSString(string: "1"), NSString(string: "2")] let secLevel = ["1": [NSString(string: "1.1"), NSString(string: "1.2")], "2": [NSString(string: "2.1"), NSString(string: "2.2")]] 

then return the saved NSString to the outlineView: child: ofItem: datasource method.

+5
source share

If you look at the NSOutlineView documentation, you will see that only pointers are stored in it; it does not save the objects returned from the child: from the method: delegate. So, when you execute this line:

 return NSString(string: output) 

You are returning a new instance of NSString that is quickly freed up (since its outline does not save it). After this point, when you ask questions about the elements, you will fail because NSString has been freed.

The solution is simple: store NSStrings in an array and return the same instances every time.

Corbin

+8
source share

This is because NSOutlineView works with objects inherited from NSObject , and the Swift line is incompatible.

0
source share

All Articles