1

I am trying to call a function 10 times at random intervals between them.

How can I achieve this?

I did come up with a method, but is is horribly ugly. It looks like this:

    var counter = 0
    NSTimer.scheduledTimerWithTimeInterval(arc4random_uniform(4)+2, target: self, selector: Selector("createNewTimer"), userInfo: nil, repeats: false)

    func createNewTimer(){
    // PERFORM STUFF YOU NEED TO
     counter++

     if counter <= 10{
        NSTimer.scheduledTimerWithTimeInterval(arc4random_uniform(4)+2, target: self, selector: Selector("createNewTimer"), userInfo: nil, repeats: false)
     }
    }

Is there a nicer way of calling function at random intervals?

kb920
  • 3,039
  • 2
  • 33
  • 44
sanjihan
  • 5,592
  • 11
  • 54
  • 119

2 Answers2

2

Try this in the playground. Hope it helps:

    func after(delay: Double, block: () -> Void) {

        let delayTime = dispatch_time(DISPATCH_TIME_NOW, Int64(delay * Double(NSEC_PER_SEC)))

        dispatch_after(delayTime, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0)) {
            block()
        }
    }

    func repeatBlock(counter: Int = 1, times: Int, block: () -> Void) {

        after(Double(arc4random_uniform(4) + 2)) {

            block()

            if counter < times {
                repeatBlock(counter + 1, times: times, block: block)
            }
        }
    }

    //client's code
    var counter = 0
    repeatBlock(times: 10) {
        //your code here
        print(NSDate())
    }
    sleep(100)
Igor B.
  • 2,219
  • 13
  • 17
  • Why do you need an `After` instance for this? You never actually use that instance for anything. Just make a top level function. Also I would be very careful about dispatching off to a global queue with this (especially when working with the UI). Dispatching to the main queue would be far better for thread safety. – Hamish Apr 16 '16 at 12:07
  • I prefer better structured code. "After" class here is a base facility which can be used somewhere else. – Igor B. Apr 16 '16 at 12:08
  • It depends whether or not to use main queue. I prefer to minimise utilisation of this queue as much as possible. If this question assumes periodic UI manipulations, then I agree with you. But that's not explicitly stated in the question. – Igor B. Apr 16 '16 at 12:13
  • Well it's not just UI updates, it's also any references you pass to your `step` or `After` functions are now potentially unsafe to use on the main thread, without having to synchronise access to the variables yourself. For example, you cannot read or write your `counter` variable on the main thread anymore – as your code will be modifying it from a background thread at some point. – Hamish Apr 16 '16 at 12:19
  • Agree that **inout** *count* variable is overkill there and can be source of race condition. I have updated the answer. – Igor B. Apr 16 '16 at 12:27
  • @originaluser2 understood your very first comment and replaced the class with method – Igor B. Apr 16 '16 at 12:45
  • More info about `dispatch_after` here: http://stackoverflow.com/questions/24034544/dispatch-after-gcd-in-swift/24318861#24318861 – John Difool Apr 16 '16 at 13:09
-2

If you need a random intervals, then I'm afraid, the above is the best solution. If the time interval was same, then you could have set it to repeats:true. But not in you case.

Varun
  • 759
  • 6
  • 12