NSOutlineView on macOS Tutorial
Discover how to display and interact with hierarchical data on macOS with this NSOutlineView on macOS tutorial. By Jean-Pierre Distler.
Sign up/Sign in
With a free Kodeco account you can download source code, track your progress, bookmark, personalise your learner profile and more!
Create accountAlready a member of Kodeco? Sign in
Sign up/Sign in
With a free Kodeco account you can download source code, track your progress, bookmark, personalise your learner profile and more!
Create accountAlready a member of Kodeco? Sign in
Contents
NSOutlineView on macOS Tutorial
25 mins
Finishing Touches
Your example application is now working, but there are at least two common behaviors missing: double-clicking to expand or collapse a group, and the ability to remove an entry from the outline view.
Let’s start with the double-click feature. Open the Assistant Editor by pressing Alt + Cmd + Enter. Open Main.storyboard in the left part of the window, and ViewController.swift in the right part.
Right-click on the outline view inside the Document Outline on the left. Inside the appearing pop-up, find doubleAction and click the small circle to its right.
Drag from the circle inside ViewController.swift and add an IBAction named doubleClickedItem
. Make sure that the sender is of type NSOutlineView
and not AnyObject
.
Switch back to the Standard editor (Cmd + Enter) and open ViewController.swift. Add the following code to the action you just created.
@IBAction func doubleClickedItem(_ sender: NSOutlineView) {
//1
let item = sender.item(atRow: sender.clickedRow)
//2
if item is Feed {
//3
if sender.isItemExpanded(item) {
sender.collapseItem(item)
} else {
sender.expandItem(item)
}
}
}
This code:
- Gets the clicked item.
- Checks whether this item is a
Feed
, which is the only item that can be expanded or collapsed. - If the item is a
Feed
, asks the outline view if the item is expanded or collapsed, and calls the appropriate method.
Build your project, then double-click a feed. It works!
The last behavior we want to implement is allowing the user to press backspace to delete the selected feed or article.
Still inside ViewController.swift, add the following method to your ViewController
. Make sure to add it to the normal declaration and not inside an extension, because the method has nothing to do with the delegate or datasource protocols.
override func keyDown(with theEvent: NSEvent) {
interpretKeyEvents([theEvent])
}
This method is called every time a key is pressed, and asks the system which key was pressed. For some keys, the system will call a corresponding action. The method called for the backspace key is deleteBackward(_:)
.
Add the method below keyDown(_:)
:
override func deleteBackward(_ sender: Any?) {
//1
let selectedRow = outlineView.selectedRow
if selectedRow == -1 {
return
}
//2
outlineView.beginUpdates()
outlineView.endUpdates()
}
- The first thing this does is see if there is something selected. If nothing is selected,
selectedRow
will have a value of -1 and you return from this method. - Otherwise, it tells the outline view that there will be updates on it and when these updates are done.
Now add the following between beginUpdates()
and endUpdates()
:
//3
if let item = outlineView.item(atRow: selectedRow) {
//4
if let item = item as? Feed {
//5
if let index = self.feeds.index( where: {$0.name == item.name} ) {
//6
self.feeds.remove(at: index)
//7
outlineView.removeItems(at: IndexSet(integer: selectedRow), inParent: nil, withAnimation: .slideLeft)
}
}
}
This code:
- Gets the selected item.
- Checks if it is a
Feed
or aFeedItem
. - If it is a
Feed
, searches the index of it inside thefeeds
array. - If found, removes it from the array.
- Removes the row for this entry from the outline view with a small animation.
To finish this method, add the code to handle FeedItems
as an else part to if let item = item as? Feed
:
else if let item = item as? FeedItem {
//8
for feed in self.feeds {
//9
if let index = feed.children.index( where: {$0.title == item.title} ) {
feed.children.remove(at: index)
outlineView.removeItems(at: IndexSet(integer: index), inParent: feed, withAnimation: .slideLeft)
}
}
}
- This code is similar to the code for a
Feed
. The only additional step is that here it iterates over all feeds, because you don’t know to whichFeed
theFeedItem
belongs. - For each
Feed
, the code checks if you can find aFeedItem
in itschildren
array. If so, it deletes it from the array and from the outline view.
Note: Not only can you delete a row, but you can also add and move rows. The steps are the same: add an item to your data model and call insertItemsAtIndexes(_:, inParent:, withAnimation:)
to insert items, or moveItemAtIndex(_:, inParent:, toIndex:, inParent:)
to move items. Make sure that your datasource is also changed accordingly.
Note: Not only can you delete a row, but you can also add and move rows. The steps are the same: add an item to your data model and call insertItemsAtIndexes(_:, inParent:, withAnimation:)
to insert items, or moveItemAtIndex(_:, inParent:, toIndex:, inParent:)
to move items. Make sure that your datasource is also changed accordingly.
Now your app is complete! Build and run to check out the new functionality you just added. Select a feed item and hit the delete key–it’ll disappear as expected. Check that the same is true for the feed as well.
Where To Go From here?
Congrats! You’ve created an RSS Feed Reader-type app with hierarchical functionality that allows the user to delete rows at will and to double-click to expand and collapse the lists.
You can download the final project here.
In this NSOutlineView on macOS tutorial you learned a lot about NSOutlineView
. You learned:
- How to hook up an
NSOutlineView
in Interface Builder. - How to populate it with data.
- How to expand/collapse items.
- How to remove entries.
- How to respond to user interactions.
There is lots of functionality that you didn’t get chance to cover here, like support for drag and drop or data models with a deeper hierarchy, so if you want to learn more about NSOutlineView
, take a look at the documentation. Since it is a subclass of NSTableView
, Ernesto García’s tutorial about table views is also worth a look.
I hope you enjoyed this NSOutlineView on macOS tutorial! If you have any questions or comments, feel free to join the forum discussion below.