向 NSRunLoop 添加计时器的正确方法
Correct way to add a timer to NSRunLoop
我正在尝试向 NSRunLoop 添加计时器。我的预期结果是,一旦将计时器添加到循环中,它们就会开始相互独立地倒计时。
我的代码现在看起来像这样:
var timer = NSTimer()
let mainRunLoop:NSRunLoop = NSRunLoop()
func blurViewActive(gestureRecognizer:UIGestureRecognizer) {
if (gestureRecognizer.state == UIGestureRecognizerState.Began){
println("STATE BEGAN")
var point = gestureRecognizer.locationInView(self.tv)
if let indexPath = self.tv.indexPathForRowAtPoint(point){
let data = messageList[indexPath.row] as Messages
if let theCell = self.tv.cellForRowAtIndexPath(indexPath) as? TableViewCell{
self.timer = NSTimer(timeInterval: 1, target: self, selector: "updateCounter", userInfo: nil, repeats: true)
self.mainRunLoop.addTimer(timer, forMode: NSRunLoopCommonModes)
mainRunLoop.run()
}
}
}
}
var counter = 10
func updateCounter(){
if counter == 0{
timer.invalidate()
}else{
counter = --counter
println(counter)
}
}
现在,按下我的按钮时似乎没有任何反应。我的理解是,一旦计时器被添加到 运行 循环中,它将独立启动 运行ning。
任何有关如何正确完成此操作的建议将不胜感激。
定时器方法总是有一个参数,即定时器对象本身。所以 "updateCounter" 作为选择器可能是错误的。
你的代码有两个问题。
首先,mainRunLoop.run()
阻塞了主线程。
使用你自己的 runloop 有点棘手,但实际上在这里没有必要。
您可以使用
在主运行循环上创建一个计时器 运行
timer = NSTimer.scheduledTimerWithTimeInterval(1, target: self, selector: "updateCounter", userInfo: nil, repeats: true)
并完全删除您的 mainRunLoop
。
另一个问题是您使用单个计时器变量和计数器。
如果您希望每个 table 视图行都有独立的计时器,那么您需要多个独立的计时器和计数器变量。
一种可能的解决方案是使用两个词典
var timerDict : [ NSIndexPath : NSTimer ] = [:]
var counterDict : [ NSIndexPath : Int ] = [:]
其中存储每个活动倒计时的计时器和当前计数器,
使用索引路径作为键。
长按时,如果有计时器,您将检查第一本词典
此行已处于活动状态,如果没有,请创建并启动一个新行:
if timerDict[indexPath] == nil {
// No timer running for this row, start a new one:
counterDict[indexPath] = 10
timerDict[indexPath] = NSTimer.scheduledTimerWithTimeInterval(1, target: self, selector: "updateCounter:",
userInfo: indexPath, repeats: true)
}
请注意,索引路径作为 userInfo:
参数传递给
定时器。然后回调方法可以检索索引路径
从传递的 timer
参数并相应地采取行动:
func updateCounter(timer : NSTimer) {
if let indexPath = timer.userInfo as? NSIndexPath {
if var counter = counterDict[indexPath] {
if counter == 0 {
// stop timer and remove from dictionaries:
timer.invalidate()
timerDict.removeValueForKey(indexPath)
counterDict.removeValueForKey(indexPath)
println("indexPath: \(indexPath) DONE")
} else {
// decrement counter and update dictionary:
--counter
println("indexPath: \(indexPath) counter: \(counter)")
counterDict[indexPath] = counter
}
}
}
}
另请注意(正如@gnasher729 在他的回答中所说),正确的类型
定时器回调是
func updateCounter(timer : NSTimer) { ... }
使用相应的选择器 "updateCounter:"
后跟一个冒号。
我正在尝试向 NSRunLoop 添加计时器。我的预期结果是,一旦将计时器添加到循环中,它们就会开始相互独立地倒计时。
我的代码现在看起来像这样:
var timer = NSTimer()
let mainRunLoop:NSRunLoop = NSRunLoop()
func blurViewActive(gestureRecognizer:UIGestureRecognizer) {
if (gestureRecognizer.state == UIGestureRecognizerState.Began){
println("STATE BEGAN")
var point = gestureRecognizer.locationInView(self.tv)
if let indexPath = self.tv.indexPathForRowAtPoint(point){
let data = messageList[indexPath.row] as Messages
if let theCell = self.tv.cellForRowAtIndexPath(indexPath) as? TableViewCell{
self.timer = NSTimer(timeInterval: 1, target: self, selector: "updateCounter", userInfo: nil, repeats: true)
self.mainRunLoop.addTimer(timer, forMode: NSRunLoopCommonModes)
mainRunLoop.run()
}
}
}
}
var counter = 10
func updateCounter(){
if counter == 0{
timer.invalidate()
}else{
counter = --counter
println(counter)
}
}
现在,按下我的按钮时似乎没有任何反应。我的理解是,一旦计时器被添加到 运行 循环中,它将独立启动 运行ning。
任何有关如何正确完成此操作的建议将不胜感激。
定时器方法总是有一个参数,即定时器对象本身。所以 "updateCounter" 作为选择器可能是错误的。
你的代码有两个问题。
首先,mainRunLoop.run()
阻塞了主线程。
使用你自己的 runloop 有点棘手,但实际上在这里没有必要。
您可以使用
timer = NSTimer.scheduledTimerWithTimeInterval(1, target: self, selector: "updateCounter", userInfo: nil, repeats: true)
并完全删除您的 mainRunLoop
。
另一个问题是您使用单个计时器变量和计数器。 如果您希望每个 table 视图行都有独立的计时器,那么您需要多个独立的计时器和计数器变量。
一种可能的解决方案是使用两个词典
var timerDict : [ NSIndexPath : NSTimer ] = [:]
var counterDict : [ NSIndexPath : Int ] = [:]
其中存储每个活动倒计时的计时器和当前计数器, 使用索引路径作为键。
长按时,如果有计时器,您将检查第一本词典 此行已处于活动状态,如果没有,请创建并启动一个新行:
if timerDict[indexPath] == nil {
// No timer running for this row, start a new one:
counterDict[indexPath] = 10
timerDict[indexPath] = NSTimer.scheduledTimerWithTimeInterval(1, target: self, selector: "updateCounter:",
userInfo: indexPath, repeats: true)
}
请注意,索引路径作为 userInfo:
参数传递给
定时器。然后回调方法可以检索索引路径
从传递的 timer
参数并相应地采取行动:
func updateCounter(timer : NSTimer) {
if let indexPath = timer.userInfo as? NSIndexPath {
if var counter = counterDict[indexPath] {
if counter == 0 {
// stop timer and remove from dictionaries:
timer.invalidate()
timerDict.removeValueForKey(indexPath)
counterDict.removeValueForKey(indexPath)
println("indexPath: \(indexPath) DONE")
} else {
// decrement counter and update dictionary:
--counter
println("indexPath: \(indexPath) counter: \(counter)")
counterDict[indexPath] = counter
}
}
}
}
另请注意(正如@gnasher729 在他的回答中所说),正确的类型 定时器回调是
func updateCounter(timer : NSTimer) { ... }
使用相应的选择器 "updateCounter:"
后跟一个冒号。