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
whileorrepeat"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