代码之家  ›  专栏  ›  技术社区  ›  marisbest2

核心数据更新时自定义UITableViewCell子类更新

  •  0
  • marisbest2  · 技术社区  · 10 年前

    我正在使用一个核心数据模型来跟踪一些资产,以及它们是否被下载以在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的抽象子类

    当发生这种情况时,电池启动KVO isDownloaded 字段,该字段是一个NSNumber,值为0,1,2,对应于DownloadState枚举,但已装箱(因为核心数据只喜欢对象,而不自动装箱,这很痛苦)。

    CourseType是三件事之一,可以是章节、课程或视频。一章有很多课,一节课有很多视频。视频处理下载,完成后,它将其isDownloaded更改为COMPLETE,即@2。家长课程是KVO倾听孩子的@“isDownloaded”中的变化。当下载了课程中的所有视频后,课程更新将被下载,父章节将听取这些更改。

    现在,一个单元可以容纳一章或一节课,我希望能够自动生成NSManagedObject子类,所以我使用类别来扩展它们。然而,这意味着我不能添加协议或使单元格成为CourseType对象的代理。所以到目前为止,我已经让Cell KVO监听CourseType对象的isDownloaded中的更改,并相应地更新其图片。然而,这意味着有时细胞在仍在收听时被解除锁定。

    因此,要么我需要知道何时从单元中删除侦听器,要么找到一种不使用KVO的方法来更新单元。

    1 回复  |  直到 10 年前
        1
  •  1
  •   Lev Landau    10 年前

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

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

    (我没有编译代码,可能包含拼写错误)