【问题标题】:Custom UITableViewCell subclass update when Core Data updatesCore Data 更新时自定义 UITableViewCell 子类更新
【发布时间】:2014-08-07 16:45:26
【问题描述】:

我正在使用 Core Data 模型来跟踪某些资产以及是否已下载它们以在 UI 中显示下载状态。类似于 Spotify 的桌面应用程序,当您根据播放器的状态有 + 或 x 或复选标记时。

我有一个自定义单元类:

// in CellClass.h
@interface CellClass : UITableViewCell

@property (strong, nonatomic) IBOutlet UILabel *mainLabel;
@property (strong, nonatomic) IBOutlet UIButton *downloadButton;
@property (strong, nonatomic) CourseType *courseTypeObject;

- (void)updateButtonPictureForStatus:(DownloadState)status;

@end

// in .m DownloadState is an enum NSUInteger
- (void)updateButtonPictureForStatus:(DownloadState)status {
    if (status == kDOWNLOAD_COMPLETE) {
        [self.downloadButton setImage:DOWNLOADED_PIC forState:UIControlStateNormal];
    }
    else if (status == kNOTDOWNLOADED) {
        [self.downloadButton setImage:NOTDOWNLOADING_PIC forState:UIControlStateNormal];
    }
    else {
        [self.downloadButton setImage:INPROCESS_PIC forState:UIControlStateNormal];
    }
    [self.downloadButton setNeedsDisplay];

}

- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context {
    if ([keyPath isEqualToString:@"courseTypeObject"]) {
        // when the object is set, add observer
        [self.courseTypeObject addObserver:self forKeyPath:@"isDownloaded" options:NSKeyValueObservingOptionNew context:nil];
        if ([change objectForKey:NSKeyValueChangeOldKey]) {
            [self.courseTypeObject removeObserver:[change objectForKey:NSKeyValueChangeOldKey] forKeyPath:@"isDownloaded"];
        }
        ///NSLog(@"should now have a courseTypeObject: %@", self.courseTypeObject);
    }
    if ([keyPath isEqualToString:@"isDownloaded"]) {
        if (object != self.courseTypeObject) {
            ///NSLog(@"weird that it got a message that wasn't his");
            return;
        }
        [self updateButtonPictureForStatus:(DownloadState)[[change objectForKey:NSKeyValueChangeNewKey] intValue]];
        ///NSLog(@"Some cell recieved message from %@ with change to state %@", object, [change objectForKey:NSKeyValueChangeNewKey]);
    }
}

@end

// in tableVC.h
@interface TableViewController : UITableViewController

@property (strong, nonatomic) CourseOffering *offering;

@end

// in tableVC.m
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
    // Return the number of rows in the section.
    return [self.offering.chapters count];
}


- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
    SOTDownloadsTableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"DownloadDetail" forIndexPath:indexPath];

    ChapterData *chapter =[self.offering.chapters objectAtIndex:indexPath.row];
    [cell.mainLabel setText:chapter.display_name];
    [cell setCourseTypeObject:chapter];
    [cell updateButtonPictureForStatus:(DownloadState)[[chapter isDownloaded] intValue]];

    return cell;
}

基本上发生的事情是,当 Cell 被创建时,它会加载到 CoureType 的子类中,这是 NSManagedObject 的抽象子类

当这种情况发生时,单元格在 isDownloaded 字段上启动 KVO,这是一个 NSNumber,其值为 0,1,2,对应于 DownloadState 枚举,但被装箱(因为 Core Data 只喜欢对象而不是自动装箱痛苦)。

CourseType 是 3 种内容之一,可以是章节、课程或视频。一章有很多课,一个课有很多视频。 Video 处理下载,完成后,它会将其 isDownloaded 更改为 COMPLETE,即@2。父课是 KVO 监听子级 @"isDownloaded" 的变化。下载课程中的所有视频后,课程更新即下载,并且父章节正在侦听这些更改。

现在单元格可以包含章节或课程,我希望能够自动生成 NSManagedObject 子类,因此我使用类别来扩展它们。但是,这意味着我不能添加协议或使单元格成为 CourseType 对象的委托。所以到目前为止,我让 Cell KVO 监听 Co​​urseType 对象的 isDownloaded 的变化,并相应地更新它的图片。但是,这意味着有时 Cell 会在仍在侦听的同时进行 Dealloc。

因此,要么我需要知道何时从单元格中删除侦听器,要么找到一种方法在没有 KVO 的情况下更新单元格。

【问题讨论】:

  • 你在执行prepareForReuse吗?
  • 没有。但是那里会发生什么?

标签: ios objective-c uitableview key-value-observing


【解决方案1】:

如果您取消订阅 dealloc 和 prepareForReuse 中的通知,事情应该是安全的。

-(void)prepareForReuse
{
    [self.courseTypeObject removeObserver:self forKeyPath:@"isDownLoaded"];
    self.courseTypeObject = nil;
}

-(void)dealloc
{
    [_courseTypeObject removeObserver:self forKeyPath:@"isDownLoaded"];
}

(我没有编译代码,可能有错别字)

【讨论】:

  • 谢谢。在 dealloc 中,我还必须删除其他观察者,但它有效。我从未见过 prepareForReuseUsed,但也许是。
  • 实际上,它被用于滚动并且似乎可以正常工作。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2016-05-28
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-04-03
  • 2020-05-25
相关资源
最近更新 更多