UITableViewCell中NSNotificationCenter观察者方法未触发问题求助
为什么
stopActivityIndicator没有被NSNotification触发? 结合你贴的代码,我梳理了几个最可能导致这个问题的原因,以及对应的解决思路:
1. 观察者注册时机晚于通知发送
你是在plusButtonClicked:方法内部才给当前cell注册观察者,但如果showCorrectBannerAfterPlusButtonClicked:(也就是发送通知的方法)在观察者完成注册之前就执行了,那这个cell根本就没来得及监听通知,自然收不到。
举个例子:点击plus按钮后,你可能先触发了某个异步请求,请求完成的回调里直接发送了通知,但这时候cell的观察者还没注册完成——这种顺序颠倒的情况很容易出现。
修复方案:
把观察者注册的代码移到cell的初始化生命周期方法里,比如awakeFromNib或者initWithStyle:reuseIdentifier:,确保cell一创建就完成监听注册:
- (void)awakeFromNib { [super awakeFromNib]; [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(stopActivityIndicator) name:@"stopActivityIndicator" object:nil]; }
2. UITableViewCell复用导致的实例丢失
UITableView的cell是复用机制,如果触发通知的时候,原来的那个cell已经被滚出屏幕、被系统回收或者复用给了其他行,那原来的cell实例已经不是当前存在的实例了,通知自然无法传递到它。
而且你只在按钮点击时注册观察者,复用后的新cell如果没触发plusButtonClicked:,就不会注册观察者,也收不到通知。
修复方案:
- 方案一:在cell的
prepareForReuse方法里处理观察者(先移除旧监听再重新注册,避免重复注册),同时在dealloc里统一清理:
- (void)prepareForReuse { [super prepareForReuse]; [[NSNotificationCenter defaultCenter] removeObserver:self name:@"stopActivityIndicator" object:nil]; [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(stopActivityIndicator) name:@"stopActivityIndicator" object:nil]; // 顺便重置UI状态 self.plusButton.hidden = NO; [self.plusButtonActivityIndicator stopAnimating]; } - (void)dealloc { [[NSNotificationCenter defaultCenter] removeObserver:self]; }
- 方案二:放弃通知,改用更直接的回调方式。比如在cell里定义一个block回调,点击plus按钮时调用block通知ViewController,操作完成后,ViewController通过tableView拿到对应的cell实例,直接调用
stopActivityIndicator方法:
// ExploreTableViewCell.h @property (nonatomic, copy) void (^plusButtonClickedBlock)(ExploreTableViewCell *cell); // ExploreTableViewCell.m - (IBAction)plusButtonClicked:(id)sender { self.plusButton.hidden = YES; [self.plusButtonActivityIndicator startAnimating]; if (self.plusButtonClickedBlock) { self.plusButtonClickedBlock(self); } } // ExploreViewController.m // 在cellForRowAtIndexPath里设置block - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { ExploreTableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"CellID" forIndexPath:indexPath]; __weak typeof(self) weakSelf = self; cell.plusButtonClickedBlock = ^(ExploreTableViewCell *clickedCell) { // 这里执行你的业务逻辑,比如请求 // 请求完成后直接调用cell的方法 [clickedCell stopActivityIndicator]; // 或者如果是异步回调,比如: dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{ [clickedCell stopActivityIndicator]; }); }; return cell; }
3. 线程不匹配(可能性较低,但值得排查)
如果通知是在子线程发送的,而你的stopActivityIndicator里有UI操作,虽然这不会导致方法不调用,但可能会引发UI异常。不过也有可能因为线程问题导致通知传递异常,你可以确保通知在主线程发送:
-(void)showCorrectBannerAfterPlusButtonClicked:(NSNotification *)notification { dispatch_async(dispatch_get_main_queue(), ^{ [[NSNotificationCenter defaultCenter] postNotificationName:@"stopActivityIndicator" object:nil]; }); }
内容的提问来源于stack exchange,提问作者JeeGee
相关产品推荐
相关产品推荐

