Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/swift/19.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Ios Swift Timer.scheduledTimer()不';行不通_Ios_Swift_Timer - Fatal编程技术网

Ios Swift Timer.scheduledTimer()不';行不通

Ios Swift Timer.scheduledTimer()不';行不通,ios,swift,timer,Ios,Swift,Timer,我的swift应用程序中有两个视图。我正在表演一段,如下所示 ViewController.swift----------------->GameViewController.swift func signIn(difficultyLvl:String){ let username = usernameTxt.text let password = passwordTxt.text let url = URL(string: "http://192.168.1.106/

我的swift应用程序中有两个视图。我正在表演一段,如下所示

ViewController.swift----------------->GameViewController.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()
}
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")
    }

}
加载GameViewController时,值数组也从ViewController.swift传递到GameViewController.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()
}
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")
    }

}
应在GameViewController.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()
}
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")
    }

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

以下是我的代码片段

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()
}
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")
    }

}
GameViewController.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()
}
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
完成闭包(在后台队列上运行)调用
performsgue
,因此它实际上也是从后台队列运行
viewdiload
。因此,计划计时器的尝试失败。要解决此问题,您必须手动将
performsgue
代码分派到主队列:

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))
这样,如果您意外地从后台队列调用了代码,它将(在调试版本中)停止应用程序


与您当前的问题无关,但另一方面,为了避免计时器和视图控制器之间的强引用循环,您通常希望保留对计时器的引用,以便在视图消失时使其失效(例如,在
视图显示中创建计时器,并在
视图显示中删除计时器). 否则,您可能会在退出后保留
GameViewController
,例如:

class GameViewController: UIViewController {

    weak 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()
    }

    @objc func setCalculationLs(_ timer: Timer) {
        print("Tick")
    }
}
或者,在iOS 10或更高版本中,您可以使用基于块的变量,并在
deinit
中引用
self
,和
invalidate

class GameViewController: UIViewController {

    weak 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")
    }

}

我觉得在定时器中设置目标对象有问题。任何建议。感谢您没有将数组发送到
GameViewController
,请在
prepare(for:sender:)
中执行此操作。
sender
参数应该是
self
到底是什么问题?GameViewController是否已加载?是否调用viewDidLoad()?阵列传递与计时器问题有何关系通常,计时器代码应该可以工作。此外,请确保从主队列调用
performsgue
。触发UI更改的东西总是必须从主线程发生。而且,巧合的是,如果您尝试在后台线程上创建计时器,它将不起作用(除非您创建运行循环,这在这里您肯定不想做)。@paper1111实际上准备(for:sender:)在我的代码中。我没能把我的问题包括进去。你能再检查一下吗?噢!成功了。非常感谢您的支持。这将对像我这样的新手非常有帮助。而且,我将尝试更改我的应用程序逻辑,不从主队列以外的任何地方启动UI更新。再次感谢您,您更喜欢[弱自我]方法还是viewDidLoad/ViewDidEvale方法?谢谢。我更喜欢
[weak self]
模式,但有时您必须使用旧的API,因为您支持旧的iOS版本。如果从技术上讲,您仍然使用旧的API,而我的示例是
viewDidLoad
/
viewdiddemouse
,那么我可能会建议
viewdide出现
viewdidemouse
(因为这些将始终保持平衡,而
viewDidLoad
可能不会与
viewdiddemove
调用保持平衡,特别是当您以模式显示另一个视图控制器时).我只使用了上面的
viewDidLoad
,因为这就是OP在原始问题中创建计时器的地方。我喜欢苹果在文档中提到计时器不适用于后台队列…等等,他们不适用。“计时器不适用于后台队列”我终于找到你了!谢谢)