True. I already had the code figured out using NSXMLDocument and a few XPath queries; another reason to stick with what I had.
Ran into the Table overflow error again with another section of AppleScriptObjC code, downloading 120 images one after another via a 120 separate NSConnections. Crash happens on 2nd or third attempt. Most users won’t be continously redownloading these images, but I think to try to make the code bug proof. This time the code is simple enough to move it back to ObjectiveC. I’m a little annoyed by the memory limits of AppleScriptObjC; you would think Apple could give it some more overhead. Speed is not really an issue for me for ASOC, it’s the table overflow and stack overflow errors. When they happen, thing behave very odd in and can affect unrelated (latter) parts of the code.
BTW, I did get my code to run with or without Garbage Collection. I just had to add an NSAutoRelease pool to main.m. I couldn’t get additional plain ASOC scripts to load as a subclass though w/o GC (seems GC helps ignoring headers), but I am able to get normal ObjectiveC classes to load w/o GC. In my testing I encountered the table overflow error with and without GC, so it is not a problem with taking out the garbage but a inherent limitation of AppleScript. Also when not using GC, dealing with objects like NSMutableArray can be more strick on how they are init’d.
I think the reason why I never found this Table overflow error before (in 13 years) is AppleScript was never taxed enough with AppleScript Studio: used do shell scripts, System Events, or another scriptable application for many operations. AppleScript just did the light lifting.
In my current project, I decided anything that will be CPU or Memory intensive will be an Objective-C class. Anything simpler will be in ASOC (App Delegate, UI, bindings). What I like about having ObjectiveC subclasses, is I can easily move them to a full fledged Cocoa app (when I am ready for that stage). Might just find a happy medium in-between. I still like ASOC. It’s easier and more fun. The GCC compiler for ObjectiveC is strick (but is helpful when you don’t know what you’re doing, it will point out all your mistakes and will sometimes make a suggestion).
Below is my same code converted to ObjectiveC. It was a good exercise for me for mainly being an AppleScript programmer. I quickly learned how to use the ‘For In ObjC 2.0 Fast-Enumeration loop’, did a little bit with booleans, and finally figured how to get StringWithFormat to work (from an NSInteger).
Not much error checking and don’t really know how to setup properties in ObjC yet. Will learn that as I go. Tried to stick with local variables and pointers. At the same time, I did hire an ObjC programmer to do their own conversion and add they added in some extra error checking / options (not included). They did a better job, but was pretty impressed that this didn’t take much time to figure out what I needed. Stumbled through it, but had the right mind set.
Both my ASOC and ObjectiveC versions run at approx. the same speed. (1 second or less to process 120,000 records). The main difference though is CPU. 10% for ObjectiveC. 90% for ASOC. For the same operation. Going back and forth using AppleScript is probably taxing.
BTW, Sticking with Xcode 4.0.2, once I got used to Xcode4, I couldn’t go back to 3.
[code]+ (NSArray *)test:(NSData *)data
{
NSError *error;
NSXMLDocument *document =
[[NSXMLDocument alloc] initWithData:data options:NSXMLDocumentTidyXML error:&error];
NSXMLElement *rootNode = [document rootElement];
//NSLog(@"my rootNode = %@", rootNode);
NSString *catQueryString =
@"//lineup-response/lineup/categories";
NSString *genreQueryString =
@"./genres";
NSString *channelQueryString =
@"./channels";
NSArray *myCategories = [rootNode nodesForXPath:catQueryString error:&error];
NSMutableArray *channels = [[NSMutableArray alloc] initWithCapacity:120];
for (NSXMLElement *cNode in myCategories)
{
NSString *myCat = [ [[cNode elementsForName:@"name"] objectAtIndex:0] stringValue];
// NSLog(@"myCat = %@", myCat);
NSArray *myGenres = [cNode nodesForXPath:genreQueryString error:&error];
// NSLog(@"myGenres = %@", myGenres);
//NSLog(@"my myCategories = %@", myCategories);
for (NSXMLElement *gNode in myGenres)
{
NSString *myGenre = [ [[gNode elementsForName:@"name"] objectAtIndex:0] stringValue];
// NSLog(@"myGenre = %@", myGenre);
NSArray *myChannels = [gNode nodesForXPath:channelQueryString error:&error];
// NSLog(@"myChannels = %@", myChannels);
for (NSXMLElement *myNode in myChannels)
{
NSString *isAvailable = [ [[myNode elementsForName:@"isAvailable"] objectAtIndex:0] stringValue];
// NSLog(@"isAvailable = %@", isAvailable);
// Convert isAvailable string to Boolean :)
BOOL availBool = [isAvailable boolValue];
if (availBool == 1)
{
NSString *myName = [ [[myNode elementsForName:@"name"] objectAtIndex:0] stringValue];
NSString *chKey = [ [[myNode elementsForName:@"channelKey"] objectAtIndex:0] stringValue];
NSString *sirNum = [ [[myNode elementsForName:@"siriusChannelNo"] objectAtIndex:0] stringValue];
// add leading zeros to the Channel Number
NSInteger sirInt = [sirNum intValue];
NSString *sirNo = [NSString stringWithFormat:@"%03d",sirInt];
NSString *logos = [[[myNode nodesForXPath:@"./logos/url" error:&error]objectAtIndex:1] stringValue];
NSString *shortDesc = [ [[myNode elementsForName:@"displayName"] objectAtIndex:0] stringValue];
[channels addObject:
[NSDictionary dictionaryWithObjectsAndKeys:
sirNo, @"sirNo",
chKey, @"chKey",
logos, @"medLogo",
shortDesc, @"shortDesc",
myName, @"chName",
myGenre, @"gen",
myCat, @"cat",
nil]];
}
}
}
}
//NSLog(@"channels = %@", channels);
[channels release];
[document release];
return channels;
}[/code]