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 or repeat "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.

enter image description here

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

Popular posts from this blog

get url and add instance to a model with prefilled foreign key :django admin -

css - Make div keyboard-scrollable in jQuery Mobile? -

ruby on rails - Seeing duplicate requests handled with Unicorn -