Finishing an action before continuing (delay, NSTimer).

I’m trying to convert a studio app into asoc, and ran into some trouble with repeat, delay, and do shell script “sleep x”. So, this is a 2 part question. Part 1:
I need to pause before continuing. In applescript studio, this was just

delay 10

I changed this to

on buttonClicked_(sender)
	performSelector_withObject_afterDelay_("logSomething:", "test", 10)
	-- do lots of stuff
end buttonClicked_

on logSomething_(x)
	log x
end logSomething

The problem with this is that while it waits to log something, it continues to “do lots of stuff” right away. I can move “do lots of stuff” into logSomething, but is there any other way to hold off until logSomething is completed before continuing?

part 2: A similar issue, but with NSTimer. Originally in studio, I had this:

repeat 10 times
	delay 3
	if (do shell script "ls ~/Downloads") contains "newFile" then
		set newFileExists to true
		exit repeat
	else
		set newFileExists to false
	end if
end repeat

The main point of the script is that after about 30 seconds, the script continues when a file name “newFile” isn’t there. I tried changing it to this in asoc:

set repeatTimer to current application's NSTimer's scheduledTimerWithTimeInterval_target_selector_userInfo_repeats_(3, me, "checkForFile:", missing value, true)
set absoluteTimer to current application's NSTimer's scheduledTimerWithTimeInterval_target_selector_userInfo_repeats_(30, me, "killTimer:", missing value, false)

on checkForFile_(sender)
	if (do shell script "ls ~/Downloads") contains "newFile" then
		set newFileExists to true
		repeatTimer's invalidate()
	end if
end checkForFile_
	
on killTimer_(sender)
	set newFileExists to false
	repeatTimer's invalidate()
end killTimer_

This also continues with the rest of the script before the 30 seconds are up and the rest of the script doesn’t know whether a new file is there or not. Is there any way to pause the rest of the script until this is done? Also, I haven’t been doing this for too long, so I might be thinking about it incorrectly, but I appreciate any input you may have. Thanks!

The short answer is :

do shell script "sleep 10"

It’s the simplest replacement for the delay command in studio.

If you need something more robust, let us know! :slight_smile:

Browser: Safari 6533.18.5
Operating System: Mac OS X (10.6)

And that’s the best solution. Generally you don’t want to stop doing things, because that can cause problems with your interface. You want your app to go about its business, except for the things you want to happen after a delay, which you put into a separate handler called either by performSelector_withObject_afterDelay_ or a timer.

This is not a good idea. One of the quirks of ASObjC (and AS) apps is that if someone hits the escape key while a do shell script is in action, the shell command gets stopped. In some cases this may be harmless, in others not so. Importantly, it can lead to the sort of intermittent problem that is very hard to track down.

If you must include a delay where you want nothing to happen, use:

tell current application's NSThread to sleepForTimeInterval_(10)

But it’s nearly always better to use a timer or performSelector_withObject_afterDelay_ (which uses a timer anyway).

Thank you for the replies. I did try to use

do shell script "sleep 10 &"

but it locks up the UI. I’m not too concerned about hitting escape as the app is a GUI for a shell script anyway, but I need the UI to stay responsive.


tell current application's NSThread to sleepForTimeInterval_(10)

I had high hopes for that, but it also locks up the UI. Also, I found performSelectorOnMainThread_withObject_waitUntilDone and thought it might work for what I need, but it also just keeps going with the script.

I can’t figure out how to get either NSTimer or performSelector_withObject_afterDelay to do what I need, which is check if a file exists every second, stop the delay and continue if it exists, or continue after 30 seconds even if it is not there. Am I looking in the right place?

You had the answer yourself in the first post: you have to move the stuff you want to happen after the delay to a handler that’s called by the delayed handler. So:

on checkForFile_(sender)
   if (do shell script "ls ~/Downloads") contains "newFile" then
       set newFileExists to true
       repeatTimer's invalidate()
       nowDoMyStuff() -- call a handler containing what needs to be done after the delay
   end if
end checkForFile_

Didn’t know about the invalidate method. What about:

current application's NSObject's cancelPreviousPerformRequestsWithTarget_(me)

would the invalidate method give the same result as this Shane?

Browser: Safari 531.22.7
Operating System: Mac OS X (10.6)

No, if it’s a timer, you use invalidate(). cancelPreviousPerformRequestsWithTarget_ is for use with performSelector_withObject_afterDelay_.

Oh, I see. Thanks! :slight_smile:

Browser: Safari 531.22.7
Operating System: Mac OS X (10.6)