Swift Timer.scheduledTimer()不起作用

我在我的快速应用程序中有两个意见。 我正在执行一个赛如下。

ViewController.swift —————–> GameViewController.swift

当加载GameViewController时,一个值数组也从ViewController.swift传递给GameViewController.swift

计时器应该在GameViewController.swift中初始化

我试图初始化一个计时器,并通过它调用一个方法,但它不起作用。

以下是我的代码片段。

ViewController.swift

func signIn(difficultyLvl:String){ let username = usernameTxt.text let password = passwordTxt.text let url = URL(string: "http://192.168.1.106/speed/scoreBoardController.php?username="+username!+"&password="+password!+"&action=SIGNIN") let task = URLSession.shared.dataTask(with: url!) {(data, response, error) in let isPassed = String(data: data!, encoding:.utf8)?.trimmingCharacters(in: CharacterSet.whitespacesAndNewlines) var gameViewControllerParams = [Int: [String: String]]() gameViewControllerParams[0] = ["userId" : isPassed!] gameViewControllerParams[1] = ["difficultyLvl" : difficultyLvl] if(isPassed != "null"){ self.performSegue(withIdentifier: "gotoGame", sender: gameViewControllerParams) } } task.resume() } 

GameViewController.swift

 class GameViewController: UIViewController { var gameViewControllerParams = [Int: [String: String]]() override func viewDidLoad() { super.viewDidLoad() let _ = Timer.scheduledTimer(timeInterval: 1.0, target:self, selector: #selector(self.setCalculationLs), userInfo:nil,repeats: true) } func setCalculationLs(){ print("Timing") } } 

定时器不能在后台队列中工作(没有一些涉及创build运行循环或在现有运行循环中手动调度它的手段)。 但是不pipe怎样,你不应该从主队列以外的任何地方启动任何UI更新。

所以,既然你从URLSession完成闭包(在后台队列上运行)调用performSegue ,它实际上也是从后台队列中运行viewDidLoad 。 因此,计划定时器的尝试失败。 为了解决这个问题,你必须手动调用执行代码到主队列中:

 let task = URLSession.shared.dataTask(with: url!) { data, response, error in ... if isPassed != "null" { DispatchQueue.main.async { self.performSegue(withIdentifier: "gotoGame", sender: ...) } } } 

如果您不确定代码是否在主队列上运行,请参阅文档 。 或者你可以使用调度前提条件:

 dispatchPrecondition(condition: .onQueue(.main)) 

这样,它将(在debugging版本中)停止应用程序,如果你不小心从后台队列中调用代码。


与您当前的问题无关,但是为了避免定时器和视图控制器之间的强引用周期,您通常需要保持对定时器的引用,以便在视图消失时invalidate (例如,创build定时器viewDidAppear并将其在viewDidDisappear删除)。 否则,你可以在被解散后保留GameViewController ,例如:

 class GameViewController: UIViewController { var timer: Timer? override func viewDidAppear(_ animated: Bool) { super.viewDidAppear(animated) timer = Timer.scheduledTimer(timeInterval: 1.0, target:self, selector: #selector(setCalculationLs), userInfo: nil, repeats: true) } override func viewDidDisappear(_ animated: Bool) { super.viewDidDisappear(animated) timer?.invalidate() } func setCalculationLs() { print("Tick") } } 

或者在iOS 10中,您可以使用基于块的变体,对self引用weak ,并在deinit invalidate

 class GameViewController: UIViewController { var timer: Timer? override func viewDidLoad() { super.viewDidLoad() timer = Timer.scheduledTimer(withTimeInterval: 1.0, repeats: true) { [weak self] timer in self?.setCalculationLs() } } deinit { timer?.invalidate() } func setCalculationLs() { print("Tick") } }