Re: Cocoa-dev Digest, Vol 3, Issue 681
Re: Cocoa-dev Digest, Vol 3, Issue 681
- Subject: Re: Cocoa-dev Digest, Vol 3, Issue 681
- From: Kirk Kerekes <email@hidden>
- Date: Mon, 22 May 2006 12:05:51 -0500
Appended is a simplistic-but-effective workaround for the requirement
that NSAppleScript execute on the main thread.
The method-of-interest is:
- (NSAppleEventDescriptor *) executeOnMainThreadReturningError:
(NSDictionary **) error;
-- which is modeled on the existing:
- (NSAppleEventDescriptor *)executeAndReturnError:(NSDictionary **)
errorInfo;
-- making this solution an easy drop-in.
This solution is appropriate when the goal is not expressly to run
the script in a subthread, but simply to allow a subthread to use the
script _as_if_ it could run in the subthread. I have found that
because of the event-synchronized scheduling of events run by
performSelectorOnMainThread:withObject:waitUntilDone:, the execution
of reasonably small AppleScripts by this method rarely causes any
serious disruption in user experience. In some cases even fairly
large scripts can be broken down into manageable sub-scripts that can
be executed serially.
If you are using AppleScript to do something irreducibly time-
consuming, you probably want to look elsewhere.
In this solution, the executeOnMainThreadReturningError: method
simply executes the script on the main thread using
performSelectorOnMainThread:withObject:waitUntilDone: and then
returns the resulting NSAppleEventDescriptor and error dictionary.
This is not a universal solution -- no support for separately
compiling the script _from_ the subthread is provided. It is assumed
that the script has either been precompiled on the main thread, or
will be compiled at execution.
It seems to cover the majority of real-world cases, however -- if you
have a totally "canned" script, it is trivial to precompile it on the
main thread, and if you don't, you are probably recreating the script
from scratch with each execution. Compiling from a subthread could
easily be added, using the current code as a model.
This could probably be implemented as a category on NSAppleScript by
using a NSMutableDictionary as the object for
performSelectorOnMainThread:withObject:waitUntilDone:, but when I
implemented this I chose the subclass route.
@interface KKNSAppleScript: NSAppleScript
{
NSAppleEventDescriptor * _resultDescriptor;
NSDictionary * _errorDict;
}
- (NSAppleEventDescriptor*)resultDescriptor;
- (void)setResultDescriptor:(NSAppleEventDescriptor*)inResultDescriptor;
- (NSDictionary*)errorDict;
- (void)setErrorDict:(NSDictionary*)inErrorDict;
- (NSAppleEventDescriptor *) executeOnMainThreadReturningError:
(NSDictionary **) error;
@end
@implementation KKNSAppleScript
- (NSAppleEventDescriptor*)resultDescriptor
{
return _resultDescriptor;
}
- (void)setResultDescriptor:(NSAppleEventDescriptor*)inResultDescriptor
{
if (_resultDescriptor != inResultDescriptor) {
[_resultDescriptor release];
_resultDescriptor = [inResultDescriptor retain];
}
}
- (NSDictionary*)errorDict
{
return _errorDict;
}
- (void)setErrorDict:(NSDictionary*)inErrorDict
{
if (_errorDict != inErrorDict) {
[_errorDict release];
_errorDict = [inErrorDict retain];
}
}
- (void) dealloc
{
[self setResultDescriptor: nil];
[self setErrorDict: nil];
[super dealloc];
}
- (void) mainThreadExecute:(id) ignored
{
NEWPOOL(pool);
NSDictionary * error = nil;
NSAppleEventDescriptor * aed = [self executeAndReturnError: &error];
[self setErrorDict: error];
[self setResultDescriptor: aed];
CLOSEPOOL(pool);
}
- (NSAppleEventDescriptor *) executeOnMainThreadReturningError:
(NSDictionary **) error
{
id temp;
[self performSelectorOnMainThread: @selector(mainThreadExecute:)
withObject: self waitUntilDone: YES];
*error = [[[self errorDict] retain] autorelease];
temp = [[[self resultDescriptor] retain] autorelease];
[self setResultDescriptor: nil];
[self setErrorDict: nil];
return temp;
}
@end
_______________________________________________
Do not post admin requests to the list. They will be ignored.
Cocoa-dev mailing list (email@hidden)
Help/Unsubscribe/Update your Subscription:
This email sent to email@hidden