Re: Problem with Converting NSApplescript to Scripting Bridge
Re: Problem with Converting NSApplescript to Scripting Bridge
- Subject: Re: Problem with Converting NSApplescript to Scripting Bridge
- From: Christopher Nebel <email@hidden>
- Date: Wed, 11 Jul 2012 12:11:21 -0700
On Jun 20, 2012, at 1:08 PM, John MacMullin <email@hidden> wrote:
> The following is the old NSApplescript, which works to create array of mailbox paths.
>
> NSAppleScript *theScript = [[[NSAppleScript alloc]initWithSource:@"tell application \"Mail\"\n set localMailboxes to every mailbox\n end tell\n"]autorelease];
> NSDictionary *theError;
> NSAppleEventDescriptor *theScriptDescriptor = [theScript executeAndReturnError: &theError];
> if (theScriptDescriptor == nil) {
> } else {
> NSString *descriptorString;
> int i, u = [theScriptDescriptor numberOfItems];
> for (i = 1; i<=u; i++) {
> descriptorString = [[[theScriptDescriptor descriptorAtIndex:i]paramDescriptorForKeyword:(AEKeyword)'seld']stringValue];
> if (descriptorString == NULL) {
> } else {
> [mailboxes_File addObject:descriptorString];
> }
> }
> }
>
> I am trying to substitute Scripting Bridge code with some difficulty. Iterating through containers, see the following, is slow by comparison to the foregoing NSApplescript. The container hierarchy involved goes down 6 levels.
>
> -(MailMailbox *)returnTheContainer:(MailMailbox *)incoming_Container
> {
> MailMailbox *returnedContainer = [incoming_Container container];
> return returnedContainer;
> }
>
> SBElementArray *allMailboxes = [mailApp mailboxes];
> int countOfAllMailboxes = [allMailboxes count];
> int i;
> for (i = 0; i < countOfAllMailboxes; i++) {
>
> NSString *mailboxName = [[allMailboxes objectAtIndex:i]name];
> MailMailbox *returnedContainer = [[allMailboxes objectAtIndex:i]container];
>
> BOOL allContainersFound = NO;
> NSMutableString *returnedPathName = [NSMutableString string];
> [returnedPathName appendString:mailboxName];
> if ([returnedContainer name] == NULL) {
> allContainersFound = YES;
> } else {
> [returnedPathName insertString:@"/" atIndex:0];
> [returnedPathName insertString:[returnedContainer name] atIndex:0];
> }
>
> while (allContainersFound == NO) {
> returnedContainer = [self returnTheContainer:(MailMailbox *)returnedContainer];
> if ([returnedContainer name] == NULL) {
> allContainersFound = YES;
> } else {
> NSString *returnedName = [returnedContainer name];
> [returnedPathName insertString:@"/" atIndex:0];
> [returnedPathName insertString:returnedName atIndex:0];
> }
> }
> [mailboxes_File addObject:returnedPathName];
> }
>
>
> I have looked at the SBOject class and tried the the following with 'seld', which returns null (I could be using it wrong also):
> - (SBObject *) propertyWithCode:(AEKeyword)code;
>
> Anyone have any experience in returning the full path directly from the MailMailbox or a way of speeding this up?
There's a difference in performance because you're going about the task in fundamentally different ways. In the first case, you're sending Mail a single "get" command to get a list of mailboxes, and then tearing apart the returned descriptors in-process -- no additional communication with Mail required. This relies on an artifact of how Mail returns mailbox specifiers, but it's fast. In the second, you're actually using Mail's scripting interface to get all the information, which is safer, but also slower: you have to send at least two "get" commands for each mailbox, and a lot more for deeply nested ones.
You could speed the second version up a bit by caching the results of non-leaf mailboxes -- as it stands, you'll get a mailbox's name once per descendant mailbox -- but your original approach is the fastest one, seeing as how Mail doesn't have a scriptable property for the mailbox's path. You were kind of on the right track by trying to use -[SBObject propertyWithCode:], but that method is used for getting a scriptable property of an object, and what you're after is simply a keyword of the raw specifier.
Unfortunately, Scripting Bridge doesn't support access to the raw specifier, at least not with public API. I will point out that the first member of the SBObject structure is an AEDesc named "_specifier", which is the specifier you need. Also, collective operations such as -makeObjectsPerformSelector and -arrayByApplyingSelector are fundamentally faster in Scripting Bridge than looping over a list, for the same reason that "get name of every mailbox" is faster than a manual loop in AppleScript. The Scripting Bridge equivalent of your original AppleScript would be "[[mailApp mailboxes] get]", and will return an NSArray of SBObjects.
--Chris Nebel
_______________________________________________
Do not post admin requests to the list. They will be ignored.
AppleScript-Users mailing list (email@hidden)
Help/Unsubscribe/Update your Subscription:
Archives: http://lists.apple.com/archives/applescript-users
This email sent to email@hidden