I read robdut’s post (http://macscripter.net/viewtopic.php?id=31515) about “delay” causing 100% CPU usage and that helped me track down many problems in my app. So I became interested in the methods mentioned in that post one being “sleep()” and the other being “NSTimer”. I tried sleep and it halt any progress bars updating text etc etc until finished. So I was wondering if someone could show me the ASOC syntax for setting up an NSTimer that gets called multiple times within a functions
the syntax using delay is currently formatted like this
on myFunction_(sender)
set textUpdate to "blah blah"
do shell script "......"
delay 2 (ideally would be replaced with NSTimer)
set textUpdate to "blah blah"
do shell script "......"
delay 2 (ideally would be replaced with NSTimer)
set textUpdate to "blah blah"
end myFunction_
You use a timer a bit differently – you set it up, and it calls a handler every time it fires. Something like this:
-- set up timer
current application's NSTimer's timerWithTimeInterval_target_selector_userInfo_repeats_(2, me, "timerFired:", "Whatever", true)
on timerFired_(theTimer)
-- do your stuff
-- To stop, use:
-- theTimer's invalidate()
end timerFired_
on myFunction_(sender)
set textUpdate to "blah blah"
do shell script "......"
performSelector_withObject_afterDelay_("myFunction2:", me, 2)
end myFunction_
on myFunction2_(sender)
set textUpdate to "blah blah"
do shell script "......"
end myFunction2_
If you want to run the shell script in background and pause the script while it runs you then can use NSTimer and check the pid etc…
on myFunction_(sender)
set textUpdate to "blah blah"
set pid to do shell script "......"
set myTimer to NSTimer's scheduledTimerWithTimeInterval_target_selector_userInfo_repeats_(1, me, "loopCheck:", missing value, true)
end myFunction_
on loopCheck_(sender)
--check for the pid in processes and if it is no longer there
--call myFunction2_(me) to proceed or clean up or whatever etc...
end loopCheck_
Shane, what is the “Whatever” for? I would like to implement this into an app of mine.
Do we have to set theTimer to anything? What does incalidate() do?
Actually, you don’t need to set the timer to anything, just saying NSTimer’s scheduledTimerWith… works ok - when the method you supply in the timer’s definition gets called the timer gets passed to it without needing a name.
I created a short program that creates some timers and shows how they behave. The nib just contains a label, a push button and a square button which are connected as indicated by the comments in the code:
[script TimersAppDelegate
property parent : class “NSObject”
property NSTimer : class “NSTimer”
property myButton : missing value --connected to a push button
property myLabel : missing value --connected to a label
property mySquare : missing value --connected to a square button
property x : 1
property plural : “”
on squarePress_(sender) --connected to the square button
myLabel's setStringValue_("I pressed the square button")
NSTimer's scheduledTimerWithTimeInterval_target_selector_userInfo_repeats_(5, me, "doSomething:", "Square button pressed", false)
NSTimer's scheduledTimerWithTimeInterval_target_selector_userInfo_repeats_(30, me, "killProgram:", "", false)
end squarePress_
on buttonPress_(sender) --connected to the push button
myLabel's setStringValue_("I pressed the push button")
NSTimer's scheduledTimerWithTimeInterval_target_selector_userInfo_repeats_(5, me, "doSomething:", "Push button pressed", false)
end buttonPress_
on doSomething_(sender) --Not connected to anything. A timer will call this method
log sender's userInfo --this will print whatever is between the parentheses in the 4th parameter of the timer to the console window
myLabel's setStringValue_("The timer fired " & x & " time" & plural)
set x to x + 1
set plural to "s"
end doSomething_
on killProgram_(sender)
tell current application's NSApp to terminate_(me)
end killProgram_
on applicationWillFinishLaunching_(aNotification)
-- Insert code here to initialize your application before any files are opened
end applicationWillFinishLaunching_
on applicationShouldTerminate_(sender)
myLabel's setStringValue_("The program is ending now")
delay 2 --This delay is here just so you can see the change in myLabel before the window disappears
return current application's NSTerminateNow
end applicationShouldTerminate_
end script
]
Notice that pushing either the push button or the square button starts a timer that calls the same method, doSomething:. You can push these buttons as many times as you want and notice both the immediate changes to myLabel as well as the 5 second delayed changes (and the log entries if you run it with the console window open).
Notice also, that pushing the square button also starts a timer that calls killProgram: which will cause the program to quit 30 seconds after you first push that button (after calling applicationShouldTerminate first).
It doesn’t work for me. I do performSelector_withObject_afterDelay_(“doSomething:”, me, 1) and it never does the function “doSomething:”, while on the first line, there is a LOGGING COMMAND! NOOO. D:
I’m not sure exactly what you’re doing, but this program works:
script SelectorAppDelegate
property parent : class "NSObject"
on doSomething_(sender)
log "Something got run"
end doSomething_
on doSomethingElse_(sender)
log "Something else got run"
end doSomethingElse_
on applicationWillFinishLaunching_(aNotification)
performSelector_withObject_afterDelay_("doSomething:", me, 1)
performSelector_withObject_afterDelay_("doSomethingElse:", me, 5)
end applicationWillFinishLaunching_
end script