NSTreeController Development: Walking the Tree
Apr/Wed/08 19:11 Filed in: iPhone SDK
Since I started developing for Mac OS X on brand new
shinny Leopard, I was able to take advantage of the
new API calls on NSTreeController to walk the tree,
access the real objects and not the proxy objects and
to insert items into the controller easier than folks
have in the past. That is what I've gathered
from reading about NSTreeController on the Internet.
The method arrangedObjects is very useful, see here: – arrangedObjects Notice that it returns a proxy root tree node containing the receiver's sorted content object. Those are some very important words and hard to explain, so instead of trying to explain, I''ll show.
NSArray *treeNodes = [[self arrangedObjects] childNodes];
So, arrangedObjects returns a proxy root tree node, so just pass that into the childNodes of NSTreeController, another useful 10.5 method, and you get all the children of the treeNode. Since I used arrangedObject, I get the top of the tree so that I can with it as I please, mostly.
Anyway here are some category classes that allow you to walk the tree using any controller selector as a callback. This example is not perfect, it is a work in progress, but useful none the less.
The code below is defined as a catagory of NSTreeController, in a garbage collected environment, so there is no memory management.
//
// NSTreeController-Extensions.h
//
// Created by Joe Michels on 3/8/08.
// Copyright 2008 Software Ops LLC. All rights reserved.
//
#import Cocoa/Cocoa.h
@interface NSTreeController (NSTreeController_Extensions)
- (void)visitAllNodesStartingWithNode: (NSArray* )treeNodes useSelector: (SEL)inSelector
withObject: (id)inObject;
@end
//
// NSTreeController-Extensions.m
// TeamPlayer
//
// Created by Joe Michels on 3/8/08.
// Copyright 2008 Software Ops LLC. All rights reserved.
//
#import "NSTreeController-Extensions.h"
#import "ProjectsController.h"
@implementation NSTreeController (NSTreeController_Extensions)
- (void)visitAllNodesStartingWithNode: (NSArray* )treeNodes
useSelector: (SEL)inSelector
withObject: (id)inObject
{
// This is a recursive decent routine. It will walk the tree visiting each node
for (id item in treeNodes)
{
NSLog( @"Visiting tree node: %@", [[item representedObject] valueForKeyPath:@"name"] );
[self performSelector:inSelector withObject:item withObject:inObject];
//check for a decendent
NSArray *childNodes = [item childNodes];
if ([childNodes count] > 0)
// we are recursing
[self visitAllNodesStartingWithNode:childNodes useSelector:inSelector withObject:inObject];
}
}
@end
Let's make a call using the above code.
- (NSArray* )itemsForScripting
{
NSLog(@"Getting projects for scripting, returned in array.");
NSArray *treeNodes = [[self arrangedObjects] childNodes];
NSMutableArray *itemsArray = [[NSMutableArray alloc] initWithCapacity: 2]; << 2??, whatever!
[self visitAllNodesStartingWithNode:treeNodes
useSelector:@selector(getOrderedListOfProjects:withArray: )
withObject:itemsArray];
return itemsArray;
}
You can pass nil for the object as in this code snipet:
NSArray *treeNodes = [[self arrangedObjects] childNodes];
[self visitAllNodesStartingWithNode:treeNodes
useSelector:@selector(findAllMatchesInNodes:withObject: )
withObject:nil];
The method arrangedObjects is very useful, see here: – arrangedObjects Notice that it returns a proxy root tree node containing the receiver's sorted content object. Those are some very important words and hard to explain, so instead of trying to explain, I''ll show.
NSArray *treeNodes = [[self arrangedObjects] childNodes];
So, arrangedObjects returns a proxy root tree node, so just pass that into the childNodes of NSTreeController, another useful 10.5 method, and you get all the children of the treeNode. Since I used arrangedObject, I get the top of the tree so that I can with it as I please, mostly.
Anyway here are some category classes that allow you to walk the tree using any controller selector as a callback. This example is not perfect, it is a work in progress, but useful none the less.
The code below is defined as a catagory of NSTreeController, in a garbage collected environment, so there is no memory management.
//
// NSTreeController-Extensions.h
//
// Created by Joe Michels on 3/8/08.
// Copyright 2008 Software Ops LLC. All rights reserved.
//
#import Cocoa/Cocoa.h
@interface NSTreeController (NSTreeController_Extensions)
- (void)visitAllNodesStartingWithNode: (NSArray* )treeNodes useSelector: (SEL)inSelector
withObject: (id)inObject;
@end
//
// NSTreeController-Extensions.m
// TeamPlayer
//
// Created by Joe Michels on 3/8/08.
// Copyright 2008 Software Ops LLC. All rights reserved.
//
#import "NSTreeController-Extensions.h"
#import "ProjectsController.h"
@implementation NSTreeController (NSTreeController_Extensions)
- (void)visitAllNodesStartingWithNode: (NSArray* )treeNodes
useSelector: (SEL)inSelector
withObject: (id)inObject
{
// This is a recursive decent routine. It will walk the tree visiting each node
for (id item in treeNodes)
{
NSLog( @"Visiting tree node: %@", [[item representedObject] valueForKeyPath:@"name"] );
[self performSelector:inSelector withObject:item withObject:inObject];
//check for a decendent
NSArray *childNodes = [item childNodes];
if ([childNodes count] > 0)
// we are recursing
[self visitAllNodesStartingWithNode:childNodes useSelector:inSelector withObject:inObject];
}
}
@end
Let's make a call using the above code.
- (NSArray* )itemsForScripting
{
NSLog(@"Getting projects for scripting, returned in array.");
NSArray *treeNodes = [[self arrangedObjects] childNodes];
NSMutableArray *itemsArray = [[NSMutableArray alloc] initWithCapacity: 2]; << 2??, whatever!
[self visitAllNodesStartingWithNode:treeNodes
useSelector:@selector(getOrderedListOfProjects:withArray: )
withObject:itemsArray];
return itemsArray;
}
You can pass nil for the object as in this code snipet:
NSArray *treeNodes = [[self arrangedObjects] childNodes];
[self visitAllNodesStartingWithNode:treeNodes
useSelector:@selector(findAllMatchesInNodes:withObject: )
withObject:nil];