Multitasking

Is there any way to have multiple handlers at once and let buttons be clicked while other handlers are active?

Not really. You can try putting stuff in separate threads and classes, but at the end of the day, all the AS in one app is run in a single instance of AppleScript, so when a subsequent thread is run, any existing threads are paused for the duration.

I’d like to understand this a bit better. It appears that the AS instance is always run in the main thread, pushing aside everything else. For example, while I’ve got a large array being modified with subroutines “row by row” and a progress bar being incremented in the main window, I lose contact with the GUI–keyboard clicks and mouse clicks are ignored until after my handlers are finished. Additionally, of course, if my app ceases to be frontmost it cannot regain focus until after the routine is completed. Is this the way it is with ASOC, or is it possible to access the main thread while still performing routines in the background? I’ve been experimenting with performSelectorInBackground_withObject_ to not much avail.

Further, would it be advantageous to try NSThread or NSOperation stuff? Or is ASOC main thread and that’s it?

Can Obj-C multitask?

Of course

Wouldn’t we all! This is how it appears to me; I welcome correction.

You can run AS on a separate thread, using performSelectorInBackground_withObject_ or NSThread. But the AS you run on other threads can’t address the UI, so you’ll need a callback to know when its completed (I tried bindings, with no success).

And essentially only one bit of AS can run at a time. If you launch a second thread, the first gets interrupted while the second is run. Here’s a bit of code that demonstrates that – connect buttonPush_ to a button and hit it several times:

	property theCount : 0
	
	on buttonPush_(sender)
		set theCount to theCount + 1
		performSelectorInBackground_withObject_("myTest", missing value)
	end buttonPush_
	
	on myTest()
		set myCount to theCount
		repeat 6 times
			log "Running test " & myCount
			delay 1
		end repeat
		log "ending test " & myCount
	end myTest

The sort of UI artefacts you describe aren’t strictly an ASObjC thing – the same thing can happen with ObjC. It happens less because (a) it’s much faster, (b) most of the stuff that takes any time is implemented asynchronously, whereas nearly all AS is synchronous, and (c) threading doesn’t have the limitations of AS.

So if you strike problem areas, you can try putting your AS in a separate thread (with no UI related stuff), and have it callback to your main script when it’s finished. But if the aim is to keep your UI responsive, you might end up making more problems for yourself if the UI widgets call yet other scripts, because these scripts may end up interrupting your other script.

So a simple calculation handler on repeat could be run with a cancel?

I don’t know about “simple”, but yes, you can have the ability to cancel, at least in theory. Something like: you’d run your repeat in a background thread, and it would call back each time to a handler that would check the value of a variable. In turn, the cancel button’s action would set this variable. You might have to hold down the cancel key for it to work, just like the old days of cancelling printing.

You can also use notifications and have the method in the separate thread check each time it loops whether it should cancel.

Good idea.

Sorry for this bump but I’ve restarted my projects and need help with this at the moment.

I need to have a background handler but still be able to access the GUI, It doesn’t need access constantly but to be able to change a progress bar 2-3 times per second without disabling buttons (or not too much), if necessary I could reduce this to once every 3-5 secs. Could a regular handler with full abilities be called each time from the background?

In Cocoa you can do this with performSelectorOnMainThread:withObject:waitUntilDone: of NSObject

Thank you :slight_smile: I’ll try it out.

There is one way I’ve worked out to run multiple tasks at the same time.

If you run a task as a shell script and /dev/null your application will send that task off to your shell and not wait (or get) a response.

This works if you don’t need a response from a task.

As an example, here’s a handler I use to set a simple timer. (I’ll use it to remind myself I have to leave for a meeting in 15 minutes, for example). I just send it a string like “15 design meeting” and after 15 minutes it Growls that message.

The key being, during those 15 minutes my application is not tied up waiting for the timer to finish. I can use it for other functions. The key is at the end of the handler where I create a shell script composed of applescript. (you need to be careful to -escape any quotes and end of lines). And then run the shell script using osascript -e and add “/dev/null” at the end.

“/dev/null/” tells the shell to run the script without waiting for a response.

As long as you don’t need the results of your task fed back into your application (and I realize that’s a big if) this enables your application to “multitask”.

Works like a charm.