NSTreeController Development: Walking the Tree
02/04/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];
|