• Open Menu Close Menu
  • Apple
  • Shopping Bag
  • Apple
  • Mac
  • iPad
  • iPhone
  • Watch
  • TV
  • Music
  • Support
  • Search apple.com
  • Shopping Bag

Lists

Open Menu Close Menu
  • Terms and Conditions
  • Lists hosted on this site
  • Email the Postmaster
  • Tips for posting to public mailing lists
Re: Script commands and the application object
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: Script commands and the application object


  • Subject: Re: Script commands and the application object
  • From: email@hidden
  • Date: Wed, 20 Mar 2002 12:07:57 -0800

Thanks to everyone who has replied, I'm slowly figuring this stuff out.

tell application "Constrictor"
set frame to {100, 100, 128, 128}
end tell

fails in all cases.

Okay, here's my guess:

I bet that the initial -valueForKey: call is being made on 'frameRect' simply to check whether the result is a single object or an array. Since you are returning an array, -makeReceiver:takeValue: decides to use the array method -replaceValueAtIndex:inPropertyWithKey:withValue: instead of the single-object -takeValue:forKey:.

A small piece of evidence that the scripting key-value coding is built with mixed single/multiple value support is in this comment in NSScriptKeyValueCoding.h:

- (id)valueAtIndex:(unsigned)index inPropertyWithKey:(NSString *)key;
// Retrieve a single value from a multi-value key. This actually works with a single-value key as well if the index is 0.
// The method valueIn<Key>AtIndex: will be used if it exists

So then the implementation of -replaceValueAtIndex:inPropertyWithKey:withValue: tries to see if you've implemented -replaceInFrame:atIndex: (see comments in that header again), sees that you haven't implemented it, and falls back on
its default strategy. It grabs the current array again with -valueForKey:, in order to stuff the new value into index 0. (As you suspected.)

The NSInternalScriptError means that during the processing something raised an NSException. Add a breakpoint to -[NSException raise] to find out where that is happening. (My guess is somewhere it is attempting to -insertObject:atIndex: on a non-mutable array, but that's just a guess.)

These guesses seem fairly good to me, and pursuing them got me to a workaround that might interest others. I implemented -replaceInFrameRect:atIndex: to check whether the value passed in is an NSArray; if it is, I just call setFrameRect: with the array and ignore the index passed to me. Thus I end up setting the key in the way I think NSSetCommand ought to be doing it in the first place.
After doing this, I saw an interesting thing in gdb: my -replaceInFrameRect:atIndex: was getting called four times! Each time, it gets passed the whole four-value NSArray, but the index passed to it goes 0, 1, 2, 3. Fascinating, eh? *Possibly* even the way it's supposed to work, but I doubt it, and in any case it isn't documented worth a bean. I chose to address this by checking the index, and if it's non-zero and the value is an array, simply ignoring the call. So only the set to index 0 takes effect, and it sets all four values. Arguably, I ought to honor all four calls, but only set the value with the given index, taking it from that index in the array passed in, setting it to that index in my state. That would mean that the set would be done in four steps, though, instead of as one atomic action, which in my case has some negative consequences.
Finally, I needed to implement what I am guessing is the correct behavior of -replaceInFrameRect:atIndex:, where it gets passed a single NSNumber as a value. I don't know whether there's even a way to make that happen from AppleScript, but if there is, my code now supports it. :->
So the final method I came up with was:

- (void)replaceInFrameRect:(id)value atIndex:(unsigned int)index
{
if ([value isKindOfClass:[NSArray class]])
{
// Work around but in NSSetCommand...
if (index == 0)
[self setFrameRect:value];
}
else if ([value respondsToSelector:@selector(intValue)])
{
int intValue = [value intValue];

if (index == 0) [self setFrameX:intValue];
else if (index == 1) [self setFrameY:intValue];
else if (index == 2) [self setFrameWidth:intValue];
else if (index == 3) [self setFrameHeight:intValue];
else
[NSException raise:NSOperationNotSupportedForKeyException format:@"index outside [0, 3] set on frameRect attribute of ConstrictorApp"];
}
else
{
[NSException raise:NSOperationNotSupportedForKeyException format:@"illegal value set on frameRect attribute of ConstrictorApp"];
}
}

I hope this helps somebody... again, thanks for the helpful pointers, I think I'll have the scriptability I want finished soon now...

Ben Haller
Stick Software
_______________________________________________
cocoa-dev mailing list | email@hidden
Help/Unsubscribe/Archives: http://www.lists.apple.com/mailman/listinfo/cocoa-dev
Do not post admin requests to the list. They will be ignored.

References: 
 >Re: Script commands and the application object (From: Greg Titus <email@hidden>)

  • Prev by Date: (repost) NSDateFormatter bug?
  • Next by Date: Can't change image of NSPopupButton
  • Previous by thread: Re: Script commands and the application object
  • Next by thread: NSThread
  • Index(es):
    • Date
    • Thread