ios - How do you setup a loop with an interval/delay? -
i'm trying make wack-a-mole game. way doing having 1 button randomly appear , disappear around screen after has tapped it. if not tap button within 1 second after reappears, disappear , find new position, reappear , wait 1 second , repeat above steps. however, whenever run code, doesn't that. moves positions if rid of 'while' statement , 'if else' statement. why won't loop, disappear, reappear, etc?
delay this: https://stackoverflow.com/a/24318861/5799228
@ibaction func movebutton(button: uibutton) { while self.wafflebutton.hidden == true || false { if self.wafflebutton.hidden == false { self.wafflebutton.hidden = true delay(3) { // find button's width , height let buttonwidth = button.frame.width let buttonheight = button.frame.height // find width , height of enclosing view let viewwidth = button.superview!.bounds.width let viewheight = button.superview!.bounds.height // compute width , height of area contain button's center let xwidth = viewwidth - buttonwidth let yheight = viewheight - buttonheight // generate random x , y offset let xoffset = cgfloat(arc4random_uniform(uint32(xwidth))) let yoffset = cgfloat(arc4random_uniform(uint32(yheight))) // offset button's center random offsets. button.center.x = xoffset + buttonwidth / 2 button.center.y = yoffset + buttonheight / 2 self.wafflebutton.hidden = false self.delay(1) { self.wafflebutton.hidden = true } } } else { delay(3) { // find button's width , height let buttonwidth = button.frame.width let buttonheight = button.frame.height // find width , height of enclosing view let viewwidth = button.superview!.bounds.width let viewheight = button.superview!.bounds.height // compute width , height of area contain button's center let xwidth = viewwidth - buttonwidth let yheight = viewheight - buttonheight // generate random x , y offset let xoffset = cgfloat(arc4random_uniform(uint32(xwidth))) let yoffset = cgfloat(arc4random_uniform(uint32(yheight))) // offset button's center random offsets. button.center.x = xoffset + buttonwidth / 2 button.center.y = yoffset + buttonheight / 2 self.wafflebutton.hidden = false self.delay(1) { self.wafflebutton.hidden = true } } } } }
you using while
in way not meant used.
this how should use while
:
var somecondition = true while somecondition { // loop fast possible untill someconditionistrue no longer true // inside while statement stuff x number of times // when ready set somecondition false somecondition = false // stop }
this how using while
:
let someconditionthatisalwaystrue = true while someconditionthatisalwaystrue { // condition true, inifinite loop... // creates function executed 3 seconds after current looping pass of while loop. // while not wait finished. // while keeps going. // fraction of second later create function execute 3 seconds later. // after 3 seconds infite amount of functions execute fraction of second between them. // except won't, since main thread still busy infinite while loop. delay(3) { // stuff } }
how right way :
don't ever use
while
orrepeat
"plan" delayed code execution.split problem in smaller problems:
issue 1 : creating loop
a loop created have 2 functions trigger each other. call them execute
, executeagain
.
so execute
triggers executeagain
, executeagain
triggers execute
, starts on again -> loop!
instead of calling execute
, executeagain
directly, create start
function. not needed place setup conditions looping function. start
call execute
, start loop.
to stop loop create stop
function changes condition. execute
, executeagain
check condition , keep on looping if check successful. stop
makes check fail.
var mustloop : bool = false func startloop() { mustloop = true execute() } func execute() { if mustloop { executeagain() } } func executeagain() { if mustloop { execute() } } func stop() { mustloop = false }
issue 2: delayed execution
if need delay inside subclass of nsobject
obvious choice nstimer
. ui classes (like uibutton
, uiviewcontroller
) subclasses of nsobject
.
nstimer
can set repeat. create loop executes every x seconds. since have 2 alternating actions makes more sense adopt more verbose looping pattern.
an nstimer
executes function (passed selector("nameoffunction")
) after x amount of time.
var timer : nstimer? func plansomething() { timer = nstimer.scheduledtimerwithtimeinterval(3, target: self, selector: selector("dosomething"), userinfo: nil, repeats: false) } func dosomething() { // stuff }
if need delay in class/struct (or don't nstimer
) can use delay
function matt posted.
it execute whatever enter in closure
after x amount of time.
func plansomething() { delay(3) { dosomething() } } func dosomething() { // stuff }
combining 2 solutions:
by using loop pattern above have distinct functions. instead of calling them directly keep loop going. insert delay method of choice , pass next function it.
so nstimer
have selector
pointing execute
or executeagain
, delay
place them in closure
how implement elegantly:
i subclass uibutton
implement this. can keep uiviewcontroller
lot cleaner. choose subclass in ib , connect iboutlet usual.
this subclass has timer
attribute replace delay. button action wacked()
set in init
method.
from uiviewcontroller
call start()
func of button. start timer
.
the timer
trigger appear()
or disappear
.
wacked()
stop timer , make button hide.
class wackingbutton : uibutton { var timer : nstimer? var hiddentime : nstimeinterval = 3 var popuptime : nstimeinterval = 1 override init(frame: cgrect) { super.init(frame: frame) self.addtarget(self, action: "wacked", forcontrolevents: uicontrolevents.touchupinside) } required init?(coder adecoder: nscoder) { super.init(coder: adecoder) self.addtarget(self, action: "wacked", forcontrolevents: uicontrolevents.touchupinside) } func start() { timer = nstimer.scheduledtimerwithtimeinterval(hiddentime, target: self, selector: selector("appear"), userinfo: nil, repeats: false) } func appear() { self.center = randomposition() self.hidden = false timer?.invalidate() timer = nstimer.scheduledtimerwithtimeinterval(popuptime, target: self, selector: selector("dissappear"), userinfo: nil, repeats: false) } func dissappear() { self.hidden = true timer?.invalidate() timer = nstimer.scheduledtimerwithtimeinterval(hiddentime, target: self, selector: selector("appear"), userinfo: nil, repeats: false) } func wacked() { self.hidden = true timer?.invalidate() } func randomposition() -> cgpoint { // find width , height of enclosing view let viewwidth = self.superview?.bounds.width ?? 0 // not correct, fails when there no superview , doesn't matter anyway. won't crash... let viewheight = self.superview?.bounds.height ?? 0 // compute width , height of area contain button's center let xwidth = viewwidth - frame.width let yheight = viewheight - frame.height // generate random x , y offset let xoffset = cgfloat(arc4random_uniform(uint32(xwidth))) let yoffset = cgfloat(arc4random_uniform(uint32(yheight))) // offset button's center random offsets. let x = xoffset + frame.width / 2 let y = yoffset + frame.height / 2 return cgpoint(x: x, y: y) } }
your uiviewcontroller
:
class viewcontroller: uiviewcontroller { @iboutlet weak var button1: wackingbutton! override func viewdidappear(animated: bool) { button1.start() } }
Comments
Post a Comment