use*_*972 5 timer nstableview grand-central-dispatch swift
我有一个由几个自定义NSTableCellView组成的tableView.一些视图必须与NSProgressIndicator一起显示计时器(已经过了多少时间).
我创建了一个计时器(带有中央显示器),每100毫秒我用setNeedsDisplay更新textView(或swift中的.needsDisplay = true).
我在具有NSTextField的常规视图中工作的代码很好,但是一旦文本字段是NSTableCellView的一部分,它就无法工作.计时器触发,但不重绘该字段.
如果我从viewController中每100毫秒重新加载整个表,它也无法工作.在任何情况下重新加载整个表都不是一个好的解决方案,因为选择每100毫秒丢失一次并且用户不能再编辑(常规)单元格.
那么我应该如何每秒在整个tableview的几个单元格中重新加载一个特定的textField呢?
@IBDesignable class ProgressCellView : NSTableCellView
{
//MARK: properties
@IBInspectable var clock : Bool = false //should this type of cell show a clock? (is set to true in interface builder)
private lazy var formatter = TimeIntervalFormatter() //move to view controller?: 1 timer for the entire table => but then selection is lost
private var timer : dispatch_source_t!
private var isRunning : Bool = false
//MARK: init
override func awakeFromNib()
{
self.timeIndex?.formatter = formatter
if self.clock
{
self.timer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, dispatch_get_main_queue())
dispatch_source_set_timer(timer, dispatch_time(DISPATCH_TIME_NOW, 0), 100 * NSEC_PER_MSEC, 50 * NSEC_PER_MSEC) //50 ms leeway, is good enough for the human eye
dispatch_source_set_event_handler(timer) {
self.timeIndex?.needsDisplay = true
//self.needsDisplay = true
//self.superview?.needsDisplay = true
}
}
}
//only run the clock when the view is visible
override func viewWillMoveToSuperview(newSuperview: NSView?)
{
super.viewWillMoveToSuperview(newSuperview)
if self.clock && !isRunning { dispatch_resume(self.timer); isRunning = true }
}
override func removeFromSuperview()
{
super.removeFromSuperview()
if self.clock && isRunning { dispatch_suspend(self.timer); isRunning = false }
}
//MARK: properties
override var objectValue: AnyObject? {
didSet {
let entry = self.objectValue as! MyEntry
self.progressBar?.doubleValue = entry.progress?.fractionCompleted ?? 0
self.timeIndex?.objectValue = entry.dateStarted
}
}
//MARK: user interface
@IBOutlet var timeIndex : NSTextField?
@IBOutlet var progressBar : NSProgressIndicator?
Run Code Online (Sandbox Code Playgroud)
}
一般来说,重新加载单元格只是为了更改它中的一个元素,更不用说它的状态是非常糟糕的,因为如你所说,它会给状态带来很多问题,动画+它也会产生滚动问题和你的重新渲染.话虽如此,这肯定是最简单的解决方案.让我们尝试在编码的概念层面上做更多的事情,因为我可以清楚地看到你有能力自己编码,并有正确的方向
控制器与视图
虽然我在这里让自己处于困境,因为总会有人对此有不同的看法,我认为这是对视图和控制器的正确使用:
解
所以现在如果我们建立了应该遵循的东西,我认为这是最好的解决方案:
即使不使用GCD,此解决方案也应该可以工作.问题是如果你有太多的更新请求,它基本上会阻塞UI并且只在有时或者从不渲染它.为此,您应该在主线程上更新UI,但在异步模式下调用,如下所示:
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0), { () -> Void in
dispatch_async(dispatch_get_main_queue(), { () -> Void in
// Do update here
})
})
Run Code Online (Sandbox Code Playgroud)