I'm experimenting with Scripting Bridge for the the first time, but have run into an issue with filtering a SBElementArray
according to a NSPredicate containing a FourCharCode enum constant as a criterion.
I wrote a trivial program to identify the "library" source in a user's iTunes library, by using -filteredArrayUsingPredicate:
to filter the SBElementArray
of all iTunes sources. I was expecting to get back an SBElementArray
that, when evaluated, would produce an array of one element, namely the library source. Instead, when I call -get
on the returned SBElementArray
, I get back an empty array.
Perplexingly, if change the order and instead call -get
on the SBElementArray
of all sources to get a concrete NSArray
, and call -filteredArrayUsingPredicate:
on this array with the same predicate as before, I do get the desired result. I don't believe this is supposed to be necessary however, and I've had success filtering a SBElementArray
using other NSPredicates (e.g. @"name=='Library'"
works fine).
The code snippet is below. iTunesESrcLibrary
is a FourCharCode constant defined in the header file generated by Scripting Bridge. (iTunesESrcLibrary = 'kLib'
). I'm running 10.6.5.
iTunesApplication* iTunes = [[SBApplication alloc] initWithBundleIdentifier:@"com.apple.iTunes"];
NSPredicate* libraryPredicate = [NSPredicate predicateWithFormat:@"kind == %u", iTunesESrcLibrary];
SBElementArray* allSources_Attempt1 = [iTunes sources];
SBElementArray* allLibrarySources_Attempt1 = (SBElementArray*)[allSources_Attempt1 filteredArrayUsingPredicate:libraryPredicate];
NSLog(@"Attempt 1: %@", allLibrarySources_Attempt1);
NSLog(@"Attempt 1 (evaluated): %@", [allLibrarySources_Attempt1 get]);
NSArray* allSources_Attempt2 = [[iTunes sources] get];
NSArray* allLibrarySources_Attempt2 = [allSources_Attempt2 filteredArrayUsingPredicate:libraryPredicate];
NSLog(@"Attempt 2: %@", allLibrarySources_Attempt2);
The output I get is the following:
Attempt 1: <SBElementArray @0x3091010: ITunesSource whose 'cmpd'{ 'relo':'= ', 'obj1':'obj '{ 'want':'prop', 'from':'exmn'($$), 'form':'prop', 'seld':'pKnd' }, 'obj2':1800169826 } of application "iTunes" (88827)>
Attempt 1 (evaluated): (
)
Attempt 2: (
"<ITunesSource @0x3091f10: ITunesSource id 65 of application \"iTunes\" (88827)>"
)
I think I've figured it out. It seems you can't simply use a FourCharCode's integer value directly in a NSPredicate
that you intend to use to filter an SBElementArray
.
By chance, I found that instead of:
[NSPredicate predicateWithFormat:@"kind == %u", iTunesESrcLibrary]
you need to use:
[NSPredicate predicateWithFormat:@"kind == %@", [NSAppleEventDescriptor descriptorWithTypeCode: iTunesESrcLibrary]]
Using this second form, I can filter the SBElementArray
sources list as expected. However, this new predicate can't be used to filter the NSArray
, even though this array is just the evaluated form of the SBElementArray
! Here, you have to switch back to the %u
version.
Rant:
Frankly this sucks, and it seems the sort of thing Scripting Bridge should deal with so I don't have to; I shouldn't have to know what an NSAppleEventDescriptor
is. And while it's reasonable that not all predicates that work with NSArray
should work with SBElementArray
, the converse should not be the case and it's unnecessarily confusing that it is.