我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,然后我在getProgress
AVMFilmsStore
发送了通知。
当我的主课程收到通知时,它会在每个所需的单元格更新中调用[tableView reloadData];
方法和progressView
。
问题是progressView
的更新仅在我滚动UITableView
虽然dataSource已更改时才会发生。
它继续我上一个问题Check progress where is necessary 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];
}
}
答案 0 :(得分:1)
您可以在此处使用键值观察(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;
}
答案 1 :(得分:0)
我认为您的问题是您在后台线程上使用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()
}
}
}