How to execute a method every second on a background thread so it doesn't affect the performance of the app
Asked Answered
G

3

5

I am trying to access my database every 30 seconds, however, whenever the method executes I can clearly see a performance dip in the application.

So far this is my current code:

var timer = Timer()

override func viewDidLoad() {
    super.viewDidLoad()
    scheduledTimerWithTimeInterval()

}

func scheduledTimerWithTimeInterval(){
    timer = Timer.scheduledTimer(timeInterval: 30, target: self, selector: #selector(self.updateCounting), userInfo: nil, repeats: true)
}

@objc func updateCounting(){
    getDatabaseInfo()
}

I am trying to do the same thing, except I would like to execute the getDatabaseInfo() method on a background thread so that the app's performance is not compromised.

Glaikit answered 26/12, 2018 at 6:14 Comment(0)
L
6

Use Grand Central Dispatch :

DispatchQueue.global(qos: .background).async {
    getDatabaseInfo()
}
Laudanum answered 26/12, 2018 at 6:20 Comment(1)
Worth mentioning that any UI updates necessary after getting database info should then be run inside a main thread, as in Nikx's answer.Aileen
R
16

You can just run the timer directly on the background queue by using a DispatchSourceTimer:

private var timer: DispatchSourceTimer?

func startTimer() {
    let queue = DispatchQueue(label: Bundle.main.bundleIdentifier! + ".timer")
    timer = DispatchSource.makeTimerSource(queue: queue)
    timer!.schedule(deadline: .now(), repeating: .seconds(1))
    timer!.setEventHandler { [weak self] in
        // do whatever stuff you want on the background queue here here

        getDatabaseInfo()

        DispatchQueue.main.async {
            // update your model objects and/or UI here
        }
    }
    timer!.resume()
}

func stopTimer() {
    timer?.cancel()
    timer = nil
}

Using Timer, you schedule it on the main queue's run loop and then have it dispatch the task to a background queue, and then dispatch UI/model updates back to the main queue. Using dispatch timer, like above, bypasses that first step, running the timer directly on a GCD background queue.

Riffraff answered 26/12, 2018 at 8:24 Comment(0)
L
6

Use Grand Central Dispatch :

DispatchQueue.global(qos: .background).async {
    getDatabaseInfo()
}
Laudanum answered 26/12, 2018 at 6:20 Comment(1)
Worth mentioning that any UI updates necessary after getting database info should then be run inside a main thread, as in Nikx's answer.Aileen
M
2

You can try with below code.

var timer = Timer()

override func viewDidLoad() {
    super.viewDidLoad()
    scheduledTimerWithTimeInterval()

}

func scheduledTimerWithTimeInterval(){
    timer = Timer.scheduledTimer(timeInterval: 30, target: self, selector: #selector(self.updateCounting), userInfo: nil, repeats: true)
}

@objc func updateCounting(){

    DispatchQueue.global(qos: .background).async {
        print("This is run on the background queue")
        getDatabaseInfo()
        DispatchQueue.main.async {
            print("This is run on the main queue, after the previous code in outer block")
        }
    }
}
Macropterous answered 26/12, 2018 at 6:22 Comment(1)
I guess, the qos parameter should be User Interactive or User Initiated and not background as it is of least priority . You can refer to the following : QOS Parameters DispatchQueueRakeoff

© 2022 - 2024 — McMap. All rights reserved.