I find that this script beeps with five second intervals and then stops. I want it to beep 10 times with five second intervals and then start to beep very quickly.
set counter to 0
repeat
beep
repeat
beep
delay 5
set counter to counter + 1
if counter is 10 then
exit repeat
end if
end repeat
end repeat
For me, having the following is no solution
set counter to 0
repeat
beep
delay 5
set counter to counter + 1
if counter is 10 then
exit repeat
end if
end repeat
repeat 10 times (*Don't need to force quit*)
beep
end repeat
Would this not work? Edit: Sounds like it wouldn’t; May be we can make it work though.
repeat 10 times
beep
delay 5
end repeat
beep 10
Edit:
Um, you sort of have it right; exit repeat in the second loop is doing what it’s supposed to do. However, the first loop goes back around and starts the second loop, and it will go on forever because counter will never be 10 again.
Maybe you want to reset the counter each time:
repeat
set counter to 0
display dialog "Primary loop"
repeat
display dialog "Secondary loop"
set counter to counter + 1
if counter is 3 then exit repeat
end repeat
end repeat
If you have a set number of times that you want it to beep, then I’d assume that you have no reason to put one repeat inside of another and try to exit just the inner one.
For how long? Since applescript can only be written linearly, there’s no way for you to be “doing something” while waiting for the repeat to end, so you have to determine how you’re going to establish when to quit repeating.
Assuming that you want to beep X times, then you could hard code it like this…
repeat 10 times
delay 5
beep
end repeat
repeat 10 times
delay 0.5
beep
end repeat
… or you could get a bit more creative and write some more portable code like this…
repeatWithDelay(10, 5)
repeatWithDelay(10, 0.5)
to repeatWithDelay(_repeat, _delay)
repeat _repeat times
beep
delay _delay
end repeat
end repeatWithDelay
Actually, I was hoping for an exit to a single repeat, not both but they would be still nested: here’s what I actually have.
tell application "iTunes"
repeat
play
set trackname to the name of the current track
set but1 to the button returned of (display dialog "Song:" & trackname & return & "Playing" buttons {"<<", "][", ">>"} with icon 1 with title "iTunes: Play")
if but1 is "<<" then
rewind
else if but1 is ">>" then
fast forward
else
pause
set but1 to the button returned of (display dialog "Song:" & trackname & return & "Paused" buttons {"quit", ">", "search"} with icon 1 with title "iTunes: Play")
if but1 is "quit" then
quit
tell application me
quit
end tell
else if but1 is ">" then
play
exit repeat
else
play
repeat
set txtr to the button returned of (display dialog "Search" buttons {"<", "Ok", ">"} with icon 1 with title "Search for song")
if txtr is "<" then
previous track
else if txtr is ">" then
next track
else
exit repeat
end if
end repeat
end if
end if
end repeat
end tell
I suppose I should have posted this the first time round, sorry.
Looking for a global exit from inner loop. Is there a simpler solution?
Beginner question. Thank you in advance for a tip how to eliminate code duplication.
set counter to 0
repeat 10 times
say "outer " & counter
repeat
say "inner " & counter
set counter to counter + 1
if counter is 4 then
say "exit inner repeat on counter = " & counter
exit repeat
end if
end repeat
if counter is 4 then
say "exit outer repeat on counter = " & counter
exit repeat
end if
end repeat
It’s usually best to try to rethink the structure so that you don’t actually need to exit it from an inner repeat. In your example, the outer repeat exits on its first iteration, so it may as well not be a repeat. The simplest answer to the OP’s query (as originally posed) would have been to replace the inner repeat with an ‘if’ condition:
set counter to 0
repeat
beep
set counter to counter + 1
if (counter ≤ 10) then delay 5
end repeat
If you do need to exit an entire nested repeat structure from an inner repeat, one idea would be to put it in its own handler, from which you could simply ‘return’ when the inner condition was met:
on doNestedRepeats()
-- Blah blah blah
repeat
-- Blah blah blah
repeat
-- Blah blah blah
repeat
-- Blah blah blah
if (conditionIsMet) then return
end repeat
end repeat
end repeat
end doNestedRepeats
doNestedRepeats()
Adding a return code would also enable the calling program to identify the specific repeat loop that was exited:
on doNestedRepeats()
-- Blah blah blah
repeat
-- Blah blah blah
if (outermostRepeatLoopConditionIsMet) then return 101
repeat
-- Blah blah blah
if (middleRepeatLoopConditionIsMet) then return 102
repeat
-- Blah blah blah
if (innermostRepeatLoopConditionIsMet) then return 103
end repeat
end repeat
end repeat
return 100
end doNestedRepeats
doNestedRepeats() returning returnCode
if returnCode = 101 then
-- The outermost repeat loop condition was met
else if returnCode = 102 then
-- The middle repeat loop condition was met
else if returnCode = 103 then
-- The innermost repeat loop condition was met
end if
An alternative approach to achieve this functionality is to enclose the nested repeat loops in a try block. A user-thrown error allows early exit from any of the nested repeat loops. Numbering the user-thrown error allows ready identification of the specific repeat loop that was exited. The user-thrown error numbers should be positive integers in order not to conflict with Applescript’s negative error numbers:
try
repeat
-- Blah blah blah
if (outermostRepeatLoopConditionIsMet) then error number 101
repeat
-- Blah blah blah
if (middleRepeatLoopConditionIsMet) then error number 102
repeat
-- Blah blah blah
if (innermostRepeatLoopConditionIsMet) then error number 103
end repeat
end repeat
end repeat
on error m number n
if n = 101 then
-- The outermost repeat loop condition was met
else if n = 102 then
-- The middle repeat loop condition was met
else if n = 103 then
-- The innermost repeat loop condition was met
else
-- Rethrow any unplanned error
error m number n
end if
end try
I want to add that I also see posts come by where the wrong repeat loop is used. Sometimes you you need more than 1 condition or in this case one condition needs to be used in different loops. Using a different loop like repeat until and repeat while could eliminate these problems as well. That is because repeat with and repeatntimes are designed to do an known amount of times while other loops are not.
There is no global exit, so to give an short answer: Not possible. When you need a programming language something to do that it’s not designed to do, your design is by definition not flawless.
The example code makes no sense in terms of how it should work. As far as I’m concerned, in terms of efficiency, the result would be the same with an single repeat with counter from 1 to 4 loop. So could you be more specific on what you exactly want so we can provide you the best possible answer? Based on your example code I would go for an additional boolean value than you can set in the inner loop and check in the other loop.
set done to false
set counter to 0
repeat 10 times
say "outer " & counter
repeat
say "inner " & counter
set counter to counter + 1
if counter is 4 then
say "exit inner repeat on counter = " & counter
set done to true
exit repeat
end if
end repeat
if done then exit repeat
end repeat
Since it seems that you’re doing nothing with the 10 loops I would change the outer loop to repeat until done so you can eliminate the last line in the main loop.