I am trying to build a tree to store USB device information. I thought that I would use NSMutableArray and NSMutableDictionary to contain this information. My problem is that I’ve never studied software engineering – I’m learning as I go – and I haven’t the faintest idea about tree theory.
I’m basing my tree on the USB Location ID, which is eight nibbles long. As I understand it, each nibble represents a layer of the tree (if you see what I mean). I’ve written a little bit of test code to see if I can build my tree properly – and, sadly, it seems that I can’t!
#import <Foundation/Foundation.h>
#define MAXCHILDREN 0xf
NSDictionary* AddItemToTree(NSDictionary* nodeEntry, unsigned int value, int depth)
{
// Convert the value into a set of nibbles
char *bytes = (char *)&value;
char byte = bytes[depth];
NSMutableDictionary* thisEntry = [[[NSMutableDictionary alloc] initWithDictionary:nodeEntry] autorelease];
if (byte == 0)
{
[thisEntry setObject:[NSString stringWithFormat:@"%08x",value] forKey:@"Value"];
[thisEntry setObject:[NSString stringWithFormat:@"%08x",byte] forKey:@"Byte"];
[thisEntry setObject:[NSNumber numberWithInt:depth] forKey:@"Depth"];
return thisEntry;
}
if(![[thisEntry allKeys]containsObject:@"ChildEntries"])
{
NSMutableArray* childArray = [[NSMutableArray alloc]init];
NSMutableDictionary* newNode = [[NSMutableDictionary alloc] init];
[childArray addObject:AddItemToTree(newNode,value,++depth)];
[thisEntry setObject:[NSNumber numberWithInt:depth] forKey:@"Depth"];
[thisEntry setObject:[NSString stringWithFormat:@"%08x",value] forKey:@"Value"];
[thisEntry setObject:[NSString stringWithFormat:@"%08x",byte] forKey:@"Byte"];
[thisEntry setObject:childArray forKey:@"ChildEntries"];
[newNode release];
[childArray release];
}
else
{
[[thisEntry objectForKey:@"ChildEntries"]addObject:AddItemToTree(thisEntry,value, ++depth)];
}
return thisEntry;
}
int main(int argc, char *argv[]) {
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
NSMutableDictionary* treenode=[[NSMutableDictionary alloc]init];
char bytearray[4] = {0x0F, 0x0F, 0x02, 0x00};
unsigned int *value = (unsigned int*)bytearray;
char bytearray2[4] = {0x0F, 0x02, 0x00, 0x00};
unsigned int *value2 = (unsigned int*)bytearray2;
char bytearray3[4] = {0x0F, 0x02, 0x00, 0x00};
unsigned int *value3 = (unsigned int*)bytearray3;
[treenode setObject:[NSNumber numberWithInt:0] forKey:@"Depth"];
[treenode setObject:[NSString stringWithFormat:@"%08x",*value] forKey:@"Value"];
[treenode setObject:AddItemToTree(treenode,*value, 0) forKey:@"ChildEntries"];
// [[treenode objectForKey:@"ChildEntries"]addObject:AddItemToTree(treenode,*value2, 0)];
[treenode writeToFile:@"/Users/headbanger/Desktop/test.plist" atomically:YES];
[pool release];
}
Adding one USB location ID works perfectly. Adding a second (by uncommenting-out the line in main) causes SIGABRT. I’m sure that it’s perfectly simple, and I’ve committed a typical newbie error. However, it’s not obvious to me and any help that you can provide would be more than welcome.
My tree will need to look something like this:
F-
|--F-
| |--2
|
|--2
This tree should be true even if an attempt is made to add the third byte array.
If you can answer the question without being USB specific then that would be most helpful, because I’d really like to understand about trees and what I’ve done wrong. That said, if there’s a quick and easy way to get a tree built for me in Objective-C then I’d love to hear it.
So please, experts, can someone tell me what I’m doing wrong? Thank you for your time.
One problem is that you set dictionary as the type of the ChildEntries:
but elsewhere you attempt to use it as a NSMutableArray (mind the addObject: method):
To fix it, in your main you could do
but even when your recursion progresses towards the 0x00 byte
if (byte==0), I think, from mentally inspecting it, that it’s going to add duplicated children and produce a reeeally deep tree.There is something wrong with your environment if you didn’t get a message warning you of the wrong method
addObjectwith the SIGABORT.Btw, it’s hard to read. Lines like these
are easier to scan and less prone to mistakes if you write:
The style is not very objective-c-ish, you could use NSUInteger and NSData instead unsigned int and char arrays.
You should first write a generic tree, then use it for your purposes. This is my tree example. It’s ugly but it’s mine. As you see, it’s common sense. You could set conditions like, two childs per node, and left child < root < right child, and then you would get a binary search tree which has better properties to find stuff. But that will take you a lot more code I guess.