[英]Notify UITableView about dataSource changes
我有UITableView
并具有随时间变化的单元格中的动态数据,即,我具有用于存储每个单元格'AVMFilmsStore'数据的对象的自定义类。 此类具有自己更新数据的方法(每10秒从服务器获取进度),例如:
-(void)getProgress{
// some operations
...
if (progress<100){
[self getProgressWithDelay:10];
}
}
而getProgressWithDelay
方法是:
-(void)getProgressWithDelay:(float)delay{
dispatch_time_t time = dispatch_time(DISPATCH_TIME_NOW,(int64_t)(delay * NSEC_PER_SEC));
dispatch_after(time,dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0), ^{
[self getProgress];
});
}
每次调用此方法后,我都会检查progress
值是否已更改,并且需要使用UITableView
告知我的主类,它必须重新绘制进度已更改的每个单元格。 我为此具有包含方法的自定义UITableViewCell
类:
-(void)styleForReady:(BOOL)isReady andProgress:(float)progress{
if(!isReady){
self.movieDate.hidden = YES;
self.movieName.hidden = YES;
self.playButton.hidden = YES;
self.settingsButton.hidden = YES;
self.progressLabel.hidden = NO;
self.progressLine.hidden = NO;
self.backgroundImage.hidden = YES;
self.progressLine.transform = CGAffineTransformMakeScale(1.0, 4.0);
self.progressLine.progressTintColor = MINT_1_0;
self.progressLabel.textColor = [UIColor blackColor];
self.bgView.hidden = YES;
self.progressLabel.text = NSLocalizedString(@"movieCreating", nil);
[self.progressLine setProgress:progress animated:YES];
} else{
self.movieDate.hidden = NO;
self.movieName.hidden = NO;
self.playButton.hidden = NO;
self.settingsButton.hidden = NO;
self.progressLabel.hidden = YES;
self.progressLine.hidden = YES;
self.backgroundImage.hidden = NO;
self.bgView.hidden = NO;
}
我在cellForRowAtIndexPath
将此方法称为:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = @"readyCell";
AVMMovieCell *cell = [self.readyTable dequeueReusableCellWithIdentifier:CellIdentifier forIndexPath:indexPath];
// Configure the cell...
if (cell == nil) {
cell = (AVMMovieCell*)[tableView dequeueReusableCellWithIdentifier:CellIdentifier forIndexPath:indexPath];
}
AVMFilmsStore *oneItem = [readyArray objectAtIndex:indexPath.row];
if (oneItem.ready==1){
[cell styleForReady:YES andProgress:100];
} else { //если идет сборка
[cell styleForReady:NO andProgress:[oneItem getProgress]];
}
return cell;
}
为了使用cellForRowAtIndexPath
通知我的班级,我在此类的viewDidLoad
方法中注册了NSNotification,然后在AVMFilmsStore
getProgress
中发送了通知。
当我的主类收到通知时,它调用[tableView reloadData];
方法和progressView
中每个需要的单元格更新。 问题是,尽管dataSource发生了更改,但我滚动UITableView
时,仅会更新progressView
。 它从我之前的问题继续进行,在需要的地方检查进度UITableView我对此问题感到非常困惑。 任何建议都会有所帮助。 很抱歉这个愚蠢的问题,但我不知道如何解决。
编辑这是我在主类中注册NSNotifications的方式:
-(void)viewDidLoad{
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(fsProgressChanged:)
name:@"filmStoreProgressChanged"
object:nil];
}
- (void)fsProgressChanged:(NSNotification *)notification
{
if ([[notification name] isEqualToString:@"filmStoreProgressChanged"]) {
[readyTable reloadData];
}
}
而如何在我发送通知AVMFilmsStore
:我有@property
readyProgress在这个类和每次我在这个方法中进行时间我保存进度到readyProgress,然后我做的:
-(void)getProgress{
// some operations
...
if (progress<100){
if(self.readyProgress!=progress){
[[NSNotificationCenter defaultCenter] postNotificationName:@"filmStoreProgressChanged" object:nil];
}
[self getProgressWithDelay:10];
}
}
您可以在此处使用键值观察(KVO)方法。 为此,您应该在单元格中保留相关AVMFilmsStore
类的属性/实例。
@property(nonatomic, strong) AVMFilmsStore *filmStore;
然后在单元格的filmStore
setter方法中为属性添加观察者,
- (void)setFilmStore:(AVMFilmsStore *)filmStore {
_filmStore = filmStore;
[_filmStore addObserver:self forKeyPath:@"ready" options:NSKeyValueObservingOptionNew | NSKeyValueObservingOptionOld context:nil];
}
然后实现方法,
-(void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context
{
if([keyPath isEqualToString:@"ready"])
{
id oldC = [change objectForKey:NSKeyValueChangeOldKey];
id newC = [change objectForKey:NSKeyValueChangeNewKey];
// Handle changes or update cell here
}
}
并在dealloc中删除观察者,
- (void)dealloc {
[_filmStore removeObserver:self forKeyPath:@"ready"];
}
在您的viewController中,
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
// Cell creation
cell.filmStore = [readyArray objectAtIndex:indexPath.row];
return cell;
}
我认为您的问题是,您正在后台线程上使用dispatch_after启动整个更新过程。 您必须确保在调用实际上将更新表的代码时,您位于主线程上。
尝试做这样的事情:
- (void)fsProgressChanged:(NSNotification *)notification
{
if ([[notification name] isEqualToString:@"filmStoreProgressChanged"]) {
dispatch_async(dispatch_get_main_queue(), ^{
[readyTable reloadData];
});
}
}
编辑:
我做了这个测试课程,可以模拟您的错误,并且修复程序有效:
class ViewController: UITableViewController {
private struct Constants {
static let Notification = "notification"
static let CellIdentifier = "cell"
}
override func viewDidLoad() {
super.viewDidLoad()
NSNotificationCenter.defaultCenter().addObserver(self, selector: "notificationFired:", name: Constants.Notification, object: nil)
tableView.reloadData()
}
override func numberOfSectionsInTableView(tableView: UITableView) -> Int {
return 1
}
override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 20
}
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier(Constants.CellIdentifier, forIndexPath: indexPath) as UITableViewCell
cell.backgroundColor = UIColor.random
return cell
}
func notificationFired(notification: NSNotification) {
dispatch_async(dispatch_get_main_queue()) { () -> Void in
self.tableView.reloadData()
}
}
@IBAction func fireNotification(sender: UIBarButtonItem) {
let time = dispatch_time(DISPATCH_TIME_NOW, Int64(1 * Double(NSEC_PER_SEC)))
dispatch_after(time, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0)) { () -> Void in
NSNotificationCenter.defaultCenter().postNotificationName(Constants.Notification, object: self)
}
}
}
private extension UIColor {
class var random : UIColor {
switch arc4random() % 5 {
case 0: return UIColor.greenColor()
case 1: return UIColor.blueColor()
case 2: return UIColor.orangeColor()
case 3: return UIColor.redColor()
case 4: return UIColor.purpleColor()
default: return UIColor.blackColor()
}
}
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.