为什么NSTimer在swift中只运行一次

时间:2016-01-17 12:40:26

标签: ios swift

我有一个http请求,如果我正确收到响应,那么我想启动一个每秒触发一次函数的计时器。该函数也是一个http请求。

这是我启动计时器的代码

    if let data = data {
        do{
            let resultJSON = try NSJSONSerialization.JSONObjectWithData(data, options: [])
            requestClient.id = resultJSON["id"] as! Double
            self.timerResponse = NSTimer.scheduledTimerWithTimeInterval(1, target: self, selector: "checkIfThereAreResponeses", userInfo: nil, repeats: true)
            self.timerResponse!.fire()
        }catch{
        }
    }

如你所见,我正在调用一个名为checkIfThereAreResponses

的函数

在该功能中,我有一个打印声明,并且该打印声明只打印一次,虽然我的计时器应该每1秒工作

我有什么遗失?

这就是功能

 func checkIfThereAreResponeses(){
    if (requestClient!.id != nil) {
        let url = NSURL(string: "http://localhost:blablabla")
        let request = NSMutableURLRequest(URL: url)
        request.HTTPMethod = "POST"

        let session = NSURLSession.sharedSession()

        task = session.dataTaskWithRequest(request, completionHandler: {(data, response, error) in
            if let error = error {
                print("error = \(error)")
            }



            if let data = data {
                do {
                    let resultJSONArray = try NSJSONSerialization.JSONObjectWithData(data, options: []) as! NSArray
        bla bla bla

                }catch {
                    print("no responses yet = \(error)")
                }
            }
        })
        task!.resume()
    }else {
        print("not yet ")
    }
}

我收到的照片 JUST ONCE no response yet

2 个答案:

答案 0 :(得分:8)

如果在完成处理程序中有此代码,建议NSTimer在主线程中运行,这可能是原因。您可能需要以下内容:

dispatch_async(dispatch_get_main_queue(), {
    // Your timer logic here
})

Apple文档说:

  

计时器与运行循环一起使用。要有效地使用计时器,   你应该知道运行循环是如何运行的 - 参见NSRunLoop。

NSTimer

  

NSRunLoop类通常不被认为是线程安全的   它的方法只能在当前的上下文中调用   线。你永远不应该尝试调用NSRunLoop的方法   对象在不同的​​线程中运行,因为这样做可能会导致   意想不到的结果。

NSRunLoop

答案 1 :(得分:2)

NSTimer通过在runloop上安排来工作。如果在会话的completionHandler中调用此方法,它将被调度到该completionHandler当前正在运行的线程的runloop。由于此线程不归您所有,而是由系统拥有,因此它将由系统处理。这可能是在completionHandler执行完毕后立即执行,或者可能要晚得多。使用该线程,runloop也会消失,因此,您的计时器可能永远不会发生,几次或只发一次;没有真正说明,因为它取决于系统何时删除线程。

因此,您应该在您拥有的线程上创建计时器,或者更容易,将计时器的创建发送到主线程(dispatch_get_main_queue()是您的朋友)。另一个选择是使用+timerWithTimeInterval...方法之一创建NSTimer,然后使用[NSRunloop mainRunloop] addTimer: yourTimer forMode NSRunLoopCommonModes]将其添加到主runloop。请记住,计时器将在与运行它的runloop相同的线程上调用选择器。

作为旁注,轮询服务器可能不是使用移动设备的最佳方式。如果您控制服务器,最好在有新数据时向设备发送推送通知。这样可以节省设备上的电量,并减少服务器的负载。但是,如果你不控制服务器,实现这一点会更复杂,然后轮询可能是一个很好的妥协。