Become a MacRumors Supporter for $50/year with no ads, ability to filter front page stories, and private forums.

Darkroom

Guest
Original poster
Dec 15, 2006
2,445
0
Montréal, Canada
i've been playing around with applescript in cocoa lately, and it seems that some scripts tend to lag more than others. i have a script that toggles autohide of the dock and it works, the problem is that if i just started the app, this script lags, even spins out before executing:

Code:
- (IBAction)showDock:(id)sender
	{
	NSString *showDockScript = @"\
				tell application \"System Events\"\n\
				tell dock preferences\n\
				set properties to {autohide:false}\n\
				end tell\n\
				end tell";
	NSDictionary* errorDict;
	NSAppleEventDescriptor *returnDescriptor = NULL;
	NSAppleScript* scriptObject = [[NSAppleScript alloc] initWithSource:showDockScript];
	returnDescriptor = [scriptObject executeAndReturnError: &errorDict];
	[NSAppleScript release];
	}

is there something wrong with the way i wrote it?

also, is it safe to say that anything applescript can do, cocoa can also do natively without the need to embed applescript?
 

hhas

macrumors regular
Oct 15, 2007
126
0
i've been playing around with applescript in cocoa lately, and it seems that some scripts tend to lag more than others. i have a script that toggles autohide of the dock and it works, the problem is that if i just started the app, this script lags, even spins out before executing:
...
is there something wrong with the way i wrote it?

It's not particularly efficient, but I can't see anything that'd cause the delays you describe. Have you tried profiling?

also, is it safe to say that anything applescript can do, cocoa can also do natively without the need to embed applescript?

Leopard's Scripting Bridge provides ObjC-Apple Event Manager bindings, although its API is somewhat obfuscated and it's prone to compatibility problems with various applications.

The other high-level option is objc-appscript (see my sig). e.g. Running your AppleScript command through its ASTranslate tool gives:

Code:
#import "SEGlue/SEGlue.h"
SEApplication *systemEvents = [SEApplication applicationWithName: @"System Events"];
SEReference *ref = [[systemEvents dockPreferences] properties];
id result = [ref setItem: [NSDictionary dictionaryWithObject: ASFalse forKey: [SEConstant autohide]]];

There are also various lower-level APIs if you need them.
 

Sayer

macrumors 6502a
Jan 4, 2002
981
0
Austin, TX
You could also move the part of code that compiles the script into an object into the startup portion of the app and simply execute it in the IBAction method.

Also there should be some new APIs in Leopard to hide elements of the screen such as the Dock and/or menu bar for kiosk/full screen purposes.
 

Darkroom

Guest
Original poster
Dec 15, 2006
2,445
0
Montréal, Canada
running this code thru instruments i get a memory spike... which i guess is like a memory leak that quickly solves itself? up and down, 32 bytes... never seen that before. the source of the spike is this line:

Code:
NSAppleScript* scriptObject = [[NSAppleScript alloc] initWithSource:showDockScript];

could that have something do do with how sometimes, often when i first launch the app, it takes a second or 2 to execute the applescript?

It's not particularly efficient, but I can't see anything that'd cause the delays you describe. Have you tried profiling?

what's profiling? :eek:

Also there should be some new APIs in Leopard to hide elements of the screen such as the Dock and/or menu bar for kiosk/full screen purposes.

previously i've used the carbon framework and SetSystemUIMode(kUIModeAllHidden, 0); to get fullscreen stuff... is that what you mean? or is there something new for leopard?
 

kainjow

Moderator emeritus
Jun 15, 2000
7,958
7
running this code thru instruments i get a memory spike... which i guess is like a memory leak that quickly solves itself? up and down, 32 bytes... never seen that before. the source of the spike is this line:

Code:
NSAppleScript* scriptObject = [[NSAppleScript alloc] initWithSource:showDockScript];

You are calling [NSAppleScript release]; but that doesn't make sense. Call [scriptObject release]; instead, or just use autorelease (which I'd suggest getting in the habit of doing, instead of calling release later).
 

Darkroom

Guest
Original poster
Dec 15, 2006
2,445
0
Montréal, Canada
You are calling [NSAppleScript release]; but that doesn't make sense. Call [scriptObject release]; instead, or just use autorelease (which I'd suggest getting in the habit of doing, instead of calling release later).

woops! missed that one :p... i have to admit that this is not the first time i've done this very thing.

memory leak is gone, but it still lags at the start.
 

Bakerman

macrumors member
Jan 31, 2005
62
7
Sweden
In my app I put the compiling of AppleScript snippets into a separate thread that runs at startup (on 10.5, so I can use NSOperation). I found that the user-experience suffers if I compile it just when it is needed, especially on older hardware.
 

Darkroom

Guest
Original poster
Dec 15, 2006
2,445
0
Montréal, Canada
so i placed the applescript that hides the dock into an object that initiates at launch, but i still get a lag... could this be on my computer only? here's my code:

Code:
- (id)init
	{
	if ([super init])
		{
		hideDockScriptObject = [[NSAppleScript alloc] initWithSource:[self hideDockScript]];
		}
	return self;
	}

- (NSString *)hideDockScript
	{
	return	@"\
		tell application \"System Events\"\n\
		tell dock preferences\n\
		set properties to {autohide:true}\n\
		end tell\n\
		end tell";
	}
	
- (IBAction)hideDock:(id)sender
	{
	NSDictionary* errorDict = nil;
	[hideDockScriptObject executeAndReturnError: &errorDict];
	
	if (errorDict)
		{
		NSLog(@"NSDictionary Error.");
		}
	}

is there something there that is tripping the system? it only stalls once, the first time the code is executed... then for the rest of the time while the app is open it's very fast.
 

kainjow

Moderator emeritus
Jun 15, 2000
7,958
7
The "lag" is probably from compiling the AppleScript and then executing it, which is what executeAndReturnError does. When you create the object in init, try compiling it there first with compileAndReturnError, so that you don't have to compile it when using it.
 

lee1210

macrumors 68040
Jan 10, 2005
3,182
3
Dallas, TX
This may be speaking from a place of misunderstanding, but since there is nothing programatically generated in your script, couldn't you just compile it, but the compiled version in your app bundle, and just run the already-compiled copy when needed? Then you never have to compile the script at runtime.

-Lee
 

Darkroom

Guest
Original poster
Dec 15, 2006
2,445
0
Montréal, Canada
it seems instant now, but i can't be really sure because sometimes it's instant if it's still cached somewhere... but i assume it's good because i've followed your advice and compiled it during init. anyway, should this make it faster? is this code correct? have i included something i shouldn't have? i only ask because i don't 100% understand NSAppleEventDescriptor *returnDescriptor.

Code:
- (id)init
	{
	if ([super init])
		{
		NSDictionary* errorDict = nil;
		showDockScriptObject = [[NSAppleScript alloc] initWithSource:[self showDockScript]];
		[showDockScriptObject compileAndReturnError:&errorDict];
		}
	return self;
	}

- (NSString *)showDockScript
	{
	return	@"\
		tell application \"System Events\"\n\
		tell dock preferences\n\
		set properties to {autohide:false}\n\
		end tell\n\
		end tell";
	}
	
- (IBAction)showDock:(id)sender
	{
	NSDictionary* errorDict = nil;
	NSAppleEventDescriptor *returnDescriptor = nil;
	returnDescriptor = [showDockScriptObject executeAndReturnError:&errorDict];
	}
 

kainjow

Moderator emeritus
Jun 15, 2000
7,958
7
It looks fine to me. If you're not using errorDict, just pass nil instead, and for returnDescriptor, just don't assign it. Makes for cleaner and easier to read code.
 
Register on MacRumors! This sidebar will go away, and you'll see fewer ads.