AppleScriptObjC and Mavericks

Just a quick heads-up. Mavericks introduces new syntax for ASObjC. In short, it uses interleaved colon-based syntax like Cocoa, rather than underscores. Old code will re-compile fine. And if you save with the new syntax in a compiled script, it will open with the old syntax under previous versions. But if you save the new syntax in a text or .applescript file, it will no longer compile if you open it on a previous version.

More later…

More info:

www.macosxautomation.com/applescript/apps/mavericks_changes.html

I’m having syntax problems with Xcode 5.0.2 under Mavericks (OS X 9.0).

I created a new project per the first tutorial (“Making Progress”) in the “APPLESCRIPTObjC EXPLORED” download.

When using an external editor, the AppleScript syntax is converted to the new interleaved style, as described in the article linked above. The project compiles and runs fine; the problem occurs after the script file is subsequently saved. Thereafter, Interface Builder no longer recognizes the App Delegate icon in the Dock as a valid target for control-drag operations from interface elements. As such, no connections can be made. Previously established connections remain intact and functional, but no new ones can be made.

-- This script is part of the materials accompanying the book 'AppleScriptObjC Explored'
-- The collection is copyright 2010-12 Shane Stanley, <sstanley@myriad-com.com.au>
-- and may not be copied without consent.
-- The code may be copied and modified freely by purchasers.



script AppDelegate
	property parent : class "NSObject"
	
	property theFilename : "App test file" -- bound property
	property theFruit : "Orange" -- bound property
	property theNumber : 10 -- bound property
	property theCounter : 0 -- bound property
	property statusMessage : "App is idle" -- bound property
	property theWindow : missing value
	property isIdle : true -- bound property
	
	on doProcess:sender
		try -- for testing
			log "Begin" -- for testing
			
			set my isIdle to false
			set deskPath to path to desktop as string
			set proposedPath to deskPath & theFilename & " (test only).txt"
			try -- in case file was left open
				tell current application to close access file proposedPath
			end try
			tell current application to set fileRef to (open for access file proposedPath with write permission)
			set eof fileRef to 0
			repeat with i from 1 to (theNumber as integer)
				
				-- set statusMessage for binding
				set my statusMessage to "Processing number " & i -- set theCounter for binding
				set my theCounter to i
				
				-- this where you would do your stuff
				write (theFruit as text) & " number " & (i as text) & return to fileRef as text
				tell theWindow to displayIfNeeded()
				do shell script "sleep 0.5"
			end repeat
			close access fileRef
			
			set my theCounter to 0
			set my statusMessage to "Finished processing " & i & " times."
			
			log "End" -- for testing
			display dialog "Finished." buttons {"OK"} default button "OK" -- for testing
		on error errMess
			log errMess
		end try
		set my isIdle to true
	end doProcess:
	
	on applicationWillFinishLaunching:aNotification
		-- Insert code here to initialize your application before any files are opened
	end applicationWillFinishLaunching:
	
	on applicationShouldTerminate:sender
		-- Insert code here to do any housekeeping before your application quits
		return current application's NSTerminateNow
	end applicationShouldTerminate:
	
end script

If the script file is reverted back to the old underscore form and saved again using the internal editor, Interface Builder once again works as expected.

-- This script is part of the materials accompanying the book 'AppleScriptObjC Explored'
-- The collection is copyright 2010-12 Shane Stanley, <sstanley@myriad-com.com.au>
-- and may not be copied without consent.
-- The code may be copied and modified freely by purchasers.



script AppDelegate
	property parent : class "NSObject"
	
	property theFilename : "App test file" -- bound property
	property theFruit : "Orange" -- bound property
	property theNumber : 10 -- bound property
	property theCounter : 0 -- bound property
	property statusMessage : "App is idle" -- bound property
	property theWindow : missing value
	property isIdle : true -- bound property
	
	on doProcess_(sender)
		try -- for testing
			log "Begin" -- for testing
			
			set my isIdle to false
			set deskPath to path to desktop as string
			set proposedPath to deskPath & theFilename & " (test only).txt"
			try -- in case file was left open
				tell current application to close access file proposedPath
			end try
			tell current application to set fileRef to (open for access file proposedPath with write permission)
			set eof fileRef to 0
			repeat with i from 1 to (theNumber as integer)
				
				-- set statusMessage for binding
				set my statusMessage to "Processing number " & i -- set theCounter for binding
				set my theCounter to i
				
				-- this where you would do your stuff
				write (theFruit as text) & " number " & (i as text) & return to fileRef as text
				tell theWindow to displayIfNeeded()
				do shell script "sleep 0.5"
			end repeat
			close access fileRef
			
			set my theCounter to 0
			set my statusMessage to "Finished processing " & i & " times."
			
			log "End" -- for testing
			display dialog "Finished." buttons {"OK"} default button "OK" -- for testing
            on error errMess
			log errMess
		end try
		set my isIdle to true
	end doProcess_
	
	on applicationWillFinishLaunching_(aNotification)
		-- Insert code here to initialize your application before any files are opened
	end applicationWillFinishLaunching_
	
	on applicationShouldTerminate_(sender)
		-- Insert code here to do any housekeeping before your application quits
		return current application's NSTerminateNow
	end applicationShouldTerminate_
	
end script

This makes it essentially impossible to use an external editor with Xcode 5. Am I doing something wrong?

I just tried it, and it worked fine here. What editor are you using?

This sounds a bit like what used to occur with an old version of AppleScript Editor – the problem was that is was saving its files as MacRoman encoding, and Xcode always assumes UTF8.

(FYI, I tried both AppleScript Editor and ASObjC Explorer.)

The results are the same with three different external editors:

AppleScript Editor (Apple)
Script Debugger 5.0.4 (Late Night Software)
ASObjC Explorer 3.0.6 (You)

Weird. Can you edit the file so it is playing up, then stuff the project and send to me?

Sent. Thank you!

OK, so there is a big problem here. I wasn’t seeing it because old links still keep working; you just can’t make new ones. So you need to edit them to the old form before making the connection. What a pain.

Hit bug report.apple.com asap…

FYI, I’ve just released a new version (3.0.7) of ASObjC Explorer for Mavericks to deal with this issue. There is a new preference setting in Preferences → Other. When checked, every time you save a .applescript file, any single-argument handlers will be changed to use old-style underscore syntax, so they will be recognised as potential action handlers when making connections in Xcode. (The new syntax will appear in Xcode and in the saved file, while the new syntax will still appear in Explorer.)

Works like a charm – thanks, Shane! :smiley:

And yes, I filed that bug report. Hopefully, Apple will respond almost as quickly as you did!

Tip 'o the hat for a great product, and even better support.

FYI, I’ve just released v3.0.9 of ASObjC Explorer, which now changes the syntax only for handlers where there is a single argument called “sender”.