我的
swift应用程序中有两个视图.我正在执行如下的segue.
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") } }
解决方法
定时器不适用于后台队列(没有一些涉及创建运行循环或在现有运行循环上手动调度它的手段).但是你绝不应该从主队列以外的任何东西发起任何UI更新.
因此,由于您从URLSession完成闭包(在后台队列上运行)调用performSegue,它实际上也在后台队列中运行viewDidLoad.因此,计划定时器的尝试失败.要解决此问题,您必须手动将performSegue代码分派到主队列:
let task = URLSession.shared.dataTask(with: url!) { data,error in ... if isPassed != "null" { DispatchQueue.main.async { self.performSegue(withIdentifier: "gotoGame",sender: ...) } } }
如果您不确定某些代码是否在主队列上运行,请参阅the documentation.或者您可以使用调度前提条件:
dispatchPrecondition(condition: .onQueue(.main))
这样,如果您不小心从后台队列中调用了代码,它将(在调试版本中)停止应用程序.
与您当前的问题无关,但另外,为了避免计时器和视图控制器之间的强引用周期,您通常希望保留对计时器的引用,以便在视图消失时使其无效(例如,创建计时器) viewDidAppear并在viewDidDisappear中删除它.否则你可以在解雇后最终保留GameViewController,例如:
class GameViewController: UIViewController { var timer: Timer? override func viewDidAppear(_ animated: Bool) { super.viewDidAppear(animated) timer = Timer.scheduledTimer(timeInterval: 1.0,selector: #selector(setCalculationLs),userInfo: nil,repeats: true) } override func viewDidDisappear(_ animated: Bool) { super.viewDidDisappear(animated) timer?.invalidate() } func setCalculationLs() { print("Tick") } }
或者在iOS 10中,您可以使用基于块的变体,对自身的弱引用,以及在deinit中无效:
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") } }