[英]How to update UITableViewCells using NSTimer and NSNotificationCentre in Swift
NOTE: Asking for answers in Swift please. 注意:请在Swift中寻求答案。
What I'm trying to do: 我正在尝试做什么:
How I'm doing it currently: 我目前是怎么做的:
I have a tableview with cells that contain a label. 我有一个包含标签的单元格的tableview。
When the cells are generated, they call a function that calculates the time between today and a stored target date, and it displays the countdown time remaining in the label. 生成单元格后,它们会调用一个函数来计算今天和存储的目标日期之间的时间,并显示标签中剩余的倒计时时间。
To get the cells to update the label every second, I use an NSTimer
that reloads the tableview every second. 为了让单元格每秒更新标签,我使用NSTimer
每秒重新加载tableview。
PROBLEM: The countdown works, but when I try to do a Swipe-to-Delete action, because the NSTimer
reloads the tableview, it resets the swiped cell so that it is no longer swiped and of course this is not acceptable for end users. 问题:倒计时有效,但是当我尝试执行“刷卡到删除”操作时,因为NSTimer
重新加载了表格视图,它会重置刷过的单元格以便不再刷卡,当然这对最终用户来说是不可接受的。
What I'm trying / Potential Solutions 我正在尝试/潜在的解决方案
I heard that a better way to do this is to use NSNotificationCenter
that is triggered by NSTimer
and add listeners to each cell. 我听说更好的方法是使用由NSTimer
触发的NSNotificationCenter
并为每个单元添加侦听器。 Every 1 second a "broadcast" is sent from the NSNotificationCenter
, the cell will receive the "broadcast" and will update the label. 每隔1秒从NSNotificationCenter
发送一次“广播”,该小区将收到“广播”并将更新标签。
I tried adding a listener to each cell in the part of the code where it generates a new cell: 我尝试在代码中生成新单元格的每个单元格中添加一个侦听器:
// Generate the cells override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell { var cell = tableView.dequeueReusableCellWithIdentifier("Tablecell", forIndexPath: indexPath) as UITableViewCell let countdownEntry = fetchedResultController.objectAtIndexPath(indexPath) as CountdownEntry // MARK: addObserver to "listen" for broadcasts NSNotificationCenter.defaultCenter().addObserver(self, selector: "updateCountdownLabel", name: mySpecialNotificationKey, object: nil) func updateCountdownLabel() { println("broadcast received in cell") if let actualLabelCountdown = labelCountdown { // calculate time between stored date to today's date var countdownValue = CountdownEngine.timeBetweenDatesRealTime(countdownEntry.date) actualLabelCountdown.text = countdownValue } }
but the observer's selector only seems to be able to target functions at the view controller level, not in the cell. 但观察者的选择器似乎只能在视图控制器级别而不是在单元格中定位功能。 (I can't get "updateCountdownLabel" to fire from within the cell. When I create a function of the same name at view controller level, the function can be called) (我无法从单元格中触发“updateCountdownLabel”。当我在视图控制器级别创建同名函数时,可以调用该函数)
Questions 问题
Thanks in advance for your help! 在此先感谢您的帮助!
It might be a solution not reloading cells at all. 它可能是一种根本不重新加载细胞的解决方案。 Just make the cells listen to an update notification and change their label accordingly. 只需让单元格听取更新通知并相应地更改其标签。 I assume you subclass UITableViewCell
and give the cell a storedDate
property. 我假设你是UITableViewCell
子类,并给单元格一个storedDate
属性。 You will set that property when preparing the cell. 您将在准备单元格时设置该属性。
The timer will just fire the notification. 计时器只会触发通知。
Remember to unregister the cell from notification center in dealloc
请记住在dealloc
从通知中心取消注册单元格
Here is a quick an dirty example. 这是一个简单的例子。
The View Controller containing your TableView: 包含TableView的View Controller:
class ViewController: UIViewController, UITableViewDataSource {
@IBOutlet weak var tableView: UITableView!
var timer: NSTimer!
//MARK: UI Updates
func fireCellsUpdate() {
let notification = NSNotification(name: "CustomCellUpdate", object: nil)
NSNotificationCenter.defaultCenter().postNotification(notification)
}
//MARK: UITableView Data Source
func numberOfSectionsInTableView(tableView: UITableView) -> Int {
return 1
}
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 10
}
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cellIdentifier = "CustomCell"
let cell = tableView.dequeueReusableCellWithIdentifier(cellIdentifier) as! CustomTableViewCell
cell.timeInterval = 20
return cell
}
//MARK: View Lifecycle
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
self.timer = NSTimer(timeInterval: 1.0, target: self, selector: Selector("fireCellsUpdate"), userInfo: nil, repeats: true)
NSRunLoop.currentRunLoop().addTimer(self.timer, forMode: NSRunLoopCommonModes)
}
deinit {
self.timer?.invalidate()
self.timer = nil
}
}
The custom cell subclass: 自定义单元子类:
class CustomTableViewCell: UITableViewCell {
@IBOutlet weak var label: UILabel!
var timeInterval: NSTimeInterval = 0 {
didSet {
self.label.text = "\(timeInterval)"
}
}
//MARK: UI Updates
func updateUI() {
if self.timeInterval > 0 {
--self.timeInterval
}
}
//MARK: Lifecycle
override func awakeFromNib() {
super.awakeFromNib()
// Initialization code
let notificationCenter = NSNotificationCenter.defaultCenter()
notificationCenter.addObserver(self, selector: Selector("updateUI"), name: "CustomCellUpdate", object: nil)
}
deinit {
NSNotificationCenter.defaultCenter().removeObserver(self)
}
}
I'm pretty sure this example doesn't adhere to your app's logic. 我很确定这个例子不符合你应用的逻辑。 Just showing how things are glowed together. 只是展示事物是如何一起发光的 。
As Ian MacDonald has suggested you should avoid reloading the cell when the timer ticks, if you are swiping. 正如Ian MacDonald建议你应该避免在计时器滴答时重新加载单元格,如果你正在滑动。 Also drop the NSNotification, as It and timer are essentially doing the samething 同时放弃NSNotification,因为它和计时器本质上是做同样的事情
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.