我正在使用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的子类中,而CoureType是NSManagedObject的抽象子类
当发生这种情况时,单元格在isDownloaded
字段上启动KVO,该字段是一个值为0,1,2的NSNumber,对应于DownloadState枚举,但是已装箱(因为Core Data只喜欢对象而不是autobox这是一种痛苦)。
CourseType是三件事之一,可以是章节,课程或视频。章节有很多课程,课程有很多视频。一个视频处理下载,当它完成时,它将其isDownloaded更改为COMPLETE,即@ 2。父课是KVO监听孩子的@“isDownloaded”的变化。下载课程中的所有视频后,课程更新将下载,并且父课程正在侦听这些更改。
现在,Cell可以包含章节或课程,我希望能够自动生成NSManagedObject子类,因此我使用类别来扩展它们。但是,这意味着我无法添加协议或使单元格成为CourseType对象的委托。到目前为止,我让Cell KVO监听CourseType对象的isDownloaded中的更改,并相应地更新其图片。但是,这意味着有时Cell仍在听取时仍然是Dealloc。
所以要么我需要知道何时从单元格中删除侦听器,要么找到一种在没有KVO的情况下更新单元格的方法。
答案 0 :(得分:1)
如果您取消订阅dealloc和prepareForReuse中的通知,则应该是安全的。
-(void)prepareForReuse
{
[self.courseTypeObject removeObserver:self forKeyPath:@"isDownLoaded"];
self.courseTypeObject = nil;
}
-(void)dealloc
{
[_courseTypeObject removeObserver:self forKeyPath:@"isDownLoaded"];
}
(我没有编译代码,可能包含拼写错误)