Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/objective-c/25.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Objective c 将KVO添加到UITableViewCell_Objective C_Core Data_Uitableview_Key Value Observing - Fatal编程技术网

Objective c 将KVO添加到UITableViewCell

Objective c 将KVO添加到UITableViewCell,objective-c,core-data,uitableview,key-value-observing,Objective C,Core Data,Uitableview,Key Value Observing,我有一个自定义UITableViewCell,它显示Person对象的各种属性(由核心数据支持)。。。一些标签、图像等。我现在强迫整个tableview在任何属性更改时重新加载,这显然是没有效率的。我知道,使用KVO,我应该能够向单元格中的标签添加一个侦听器,该标签可以侦听个人属性的更改。但我不知道如何实现它,也找不到任何例子 以下是我通常在UITableView的CellForRowatineXpath中执行的操作: - (UITableViewCell *) tableView: (

我有一个自定义UITableViewCell,它显示Person对象的各种属性(由核心数据支持)。。。一些标签、图像等。我现在强迫整个tableview在任何属性更改时重新加载,这显然是没有效率的。我知道,使用KVO,我应该能够向单元格中的标签添加一个侦听器,该标签可以侦听个人属性的更改。但我不知道如何实现它,也找不到任何例子

以下是我通常在UITableView的CellForRowatineXpath中执行的操作:

    - (UITableViewCell *) tableView: (UITableView *) tableView cellForRowAtIndexPath: (NSIndexPath *) indexPath
    {
        static NSString *simple = @"CustomCellId";

        CustomCell *cell = (CustomCell *) [tableView dequeueReusableCellWithIdentifier:simple];

        if (cell == nil)
        {
            NSArray *nib =  [[NSBundle mainBundle] loadNibNamed:@"CustomCell" owner:self options:nil];

            for (id findCell in nib )
            {
                if ( [findCell isKindOfClass: [CustomCell class]])
                {
                    cell = findCell;
                }    
            }
         }
         Person *managedObject = [self.someArray objectAtIndex: indexPath.row];
         cell.namelabel.text =  managedObject.displayName;
         return cell;
}
该单元连接在IB中。我希望检测displayName何时更改,并只更新名称标签。
感谢您提供的背景资料,如果您还没有阅读过键值观察和键值编码指南,您可能需要阅读这些指南。然后回顾NSKeyValueObserving类别方法

简而言之,您需要小心地将观察对象添加和删除到观察者的观察对象列表中(请原谅该语句看似冗余)。你不想让一个对象在观察员仍然注册的情况下消失,或者你会收到投诉和其他可能的问题

也就是说,您可以使用
-addObserver:keyPath:options:context
将对象添加为观察者。上下文应该是静态声明的字符串。options参数控制在观察方法中返回的数据(见下文)。keyPath是特性名称从观察对象到观察特性的路径(这可能会遍历多个对象,并且会在中间对象更改时更新,而不仅仅是在叶特性更改时更新)

在您的情况下,您可以观察标签,并使用
text
keyPath或单元格,然后使用
namelab.text
keyPath。如果table view类的设计不同,则可以观察整个单元格数组,但UITableView上没有此类属性。观察单元格的问题是,表视图可能随时删除它(如果您的设计在可变长度列表中使用多个用于相同目的的单元格)。如果你知道你的细胞是静止的,你可以毫无顾虑地观察它们

注册了观察者后,该观察者必须实现
-observeValueForKeyPath:ofObject:change:context:
,确认上下文匹配(只需将指针值与静态字符串的地址进行比较;否则,调用super的实现),然后在更改字典中查找所需的数据(或直接向对象请求)并使用它来更新您认为合适的模型

示例代码中有许多KVO示例,包括苹果的开发者网站,以及Malcolm Crawford(mmalc)网站上绑定示例的一部分,但大多数示例都是针对Mac OS X的,而不是iOS。

这可以:

在configureCell中:

[managedObject addObserver: cell forKeyPath: @"displayName" options:NSKeyValueObservingOptionNew context: @"Context"];
在自定义单元格中:

- (void)observeValueForKeyPath:(NSString *)keyPath
                      ofObject:(id)object
                        change:(NSDictionary *)change
                       context:(void *)context
{
    Person *label = (Person *) object;
    self.namelabel.text = [label valueForKey:@"displayName"];
}

上述答案对于静态电池来说是非常好的。将KVO用于
UITableViewCell
s仍然可以实现单元重用。在单元格即将显示时添加所需的观察者,并在单元格不再显示时删除它们。唯一的诀窍是,苹果在发送DiEndDisplayingCell:时似乎前后不一致,因此需要在iOS 6.1上删除两个位置的观察者

@implementation MyTableViewCell

@property MyTableViewController * __weak parentTVC;

- (UITableViewCell *)tableView:(UITableView *)tableView 
cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
    ((MyTableViewCell *)cell).parentTVC = self;
    // Don't add observers, or the app may crash later when cells are recycled
}


- (void)tableView:(UITableView *)tableView 
  willDisplayCell:(HKTimelineCell *)cell 
forRowAtIndexPath:(NSIndexPath *)indexPath
{
    // Add observers
}

- (void)tableView:(UITableView *)tableView 
didEndDisplayingCell:(UITableViewCell *)cell 
forRowAtIndexPath:(NSIndexPath *)indexPath
{
    [self removeMyKVOObservers];
}

- (void)viewWillDisappear:(BOOL)animated
{
    for (MyTableViewCell *cell in self.visibleCells) {
        // note! didEndDisplayingCell: isn't sent when the entire controller is going away! 
        [self removeMyKVOObservers];
    }
}
如果未清理观察者,可能会发生以下情况。观察者可能会尝试通知该内存位置上的任何对象,这些对象甚至可能不存在

(
)

在我的例子中,我使用选项(
NSKeyValueObservingOptionNew
|
NSKeyValueObservingOptionOld
)向自定义单元格标签forKeyPath“text”添加了一个观察者

当观察键路径的值时,我检查以确保键路径是我想要的,这是一个额外的度量,然后我调用我的方法来执行我想要在该标签上执行的任何操作

e、 g就我而言

-(id)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier
{
    self = [super initWithStyle:style reuseIdentifier:reuseIdentifier];

    if (self) {
        // Helpers
        CGSize cellSize = self.contentView.frame.size;

        CGRect sizerFrame = CGRectZero;
        sizerFrame.origin.x = kDefaultUITableViewCellContentLeftInset;
        sizerFrame.origin.y = kDefaultUITableViewCellContentTopInset;

        // The Profile Image
        CGRect imageFrame = CGRectMake(sizerFrame.origin.x, sizerFrame.origin.y, kDefaultProfilePictureSizeBWidth, kDefaultProfilePictureSizeBHeight);
        self.userProfilePictureUIImageView = [[UIImageView alloc] initWithFrame:imageFrame];
        [self.userProfilePictureUIImageView setImage:[UIImage imageNamed:@"placeholderImage"]];
        [ApplicationUtilities formatViewLayer:self.userProfilePictureUIImageView withBorderRadius:4.0];

        // adjust the image content mode based on the lenght of it's sides
        CGSize avatarSize = self.userProfilePictureUIImageView.image.size;

        if (avatarSize.width < avatarSize.height) {
            [self.userProfilePictureUIImageView setContentMode:UIViewContentModeScaleAspectFill];
        } else {
            [self.userProfilePictureUIImageView setContentMode:UIViewContentModeScaleAspectFit];
        }

        CGFloat readStateSize = 10.0;
        CGRect readStateFrame = CGRectMake((imageFrame.origin.x + imageFrame.size.width) - readStateSize, CGRectGetMaxY(imageFrame) + 4, readStateSize, readStateSize);

        // Read State
        self.readStateUIImageView = [[UIImageView alloc] initWithFrame:readStateFrame];
        self.readStateUIImageView.backgroundColor = RGBA2UIColor(0.0, 157.0, 255.0, 1.0);
        [ApplicationUtilities formatViewLayer:self.readStateUIImageView withBorderRadius:readStateSize/2];


        sizerFrame.origin.x = CGRectGetMaxX(imageFrame) + kDefaultViewContentHorizontalSpacing;
        // read just the width of the senders label based on the width of the message label
        CGRect messageLabelFrame = sizerFrame;
        messageLabelFrame.size.width = cellSize.width - (CGRectGetMinX(messageLabelFrame) + kDefaultViewContentHorizontalSpacing);
        messageLabelFrame.size.height = kDefaultInitialUILabelHeight;

        // Store the original frame for resizing
        initialLabelFrame = messageLabelFrame;

        self.messageLabel = [[UILabel alloc]initWithFrame:messageLabelFrame];
        [self.messageLabel setBackgroundColor:[UIColor clearColor]];
        [self.messageLabel setFont:[UIFont systemFontOfSize:14.0]];
        [self.messageLabel setTextColor:[UIColor blackColor]];
        [self.messageLabel setNumberOfLines:2];
        [self.messageLabel setText:@""];

        // Modify Sizer Frame for Message Date Label
        sizerFrame = initialLabelFrame;
        // Modify the y offset
        sizerFrame.origin.y = CGRectGetMaxY(sizerFrame) + kDefaultViewContentVerticalSpacing;

        // Message Date
        self.messageDateLabel = [[UILabel alloc] initWithFrame:CGRectZero];
        [self.messageDateLabel setBackgroundColor:[UIColor clearColor]];
        [self.messageDateLabel setFont:[UIFont systemFontOfSize:12.0]];
        [self.messageDateLabel setTextColor:RGBA2UIColor(200.0, 200.0, 200.0, 1.0)];
        [self.messageDateLabel setHighlightedTextColor:[UIColor whiteColor]];
        [self.messageDateLabel setTextAlignment:NSTextAlignmentRight];
        [self.messageDateLabel setNumberOfLines:1];
        [self.messageDateLabel setText:@"Message Date"];
        [self.messageDateLabel sizeToFit];

        [self.contentView addSubview:self.userProfilePictureUIImageView];
        [self.contentView addSubview:self.readStateUIImageView];
        [self.contentView addSubview:self.messageDateLabel];
        [self.contentView addSubview:self.messageLabel];

        // Add KVO for all text labels
        [self.messageDateLabel addObserver:self forKeyPath:@"text" options:(NSKeyValueObservingOptionNew | NSKeyValueObservingOptionOld) context:NULL];
        [self.messageLabel addObserver:self forKeyPath:@"text" options:(NSKeyValueObservingOptionNew | NSKeyValueObservingOptionOld) context:NULL];

    }
    return self;
}

-(void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context
{
    if ([keyPath isEqual:@"text"]) {

        [self resizeCellObjects];
    }
}

-(void)resizeCellObjects
{
    // Resize and reposition the message label
    CGRect messageLabelFrame = initialLabelFrame;

    self.messageLabel.frame = messageLabelFrame;
    [self.messageLabel setNumberOfLines:2];
    [self.messageLabel sizeToFit];

    // Resize the messageDate label
    CGRect messageDateFrame = initialLabelFrame;
    messageDateFrame.origin.y = CGRectGetMaxY(self.messageLabel.frame) + kDefaultViewContentVerticalSpacing;
    self.messageDateLabel.frame = messageDateFrame;

    [self.messageDateLabel sizeToFit];

}
-(id)initWithStyle:(UITableViewCellStyle)样式重用标识符:(NSString*)重用标识符
{
self=[super-initWithStyle:style-reuseIdentifier:reuseIdentifier];
如果(自我){
//助手
CGSize cellSize=self.contentView.frame.size;
CGRect sizerFrame=CGRectZero;
sizerFrame.origin.x=kDefaultUITableViewCellContentLeftInset;
sizerFrame.origin.y=kDefaultUITableViewCellContentTopInset;
//配置文件图像
CGRect imageFrame=CGRectMake(sizerFrame.origin.x,sizerFrame.origin.y,kDefaultProfilePictureSizeBWidth,kDefaultProfilePictureSizeBHeight);
self.userProfilePictureUIImageView=[[UIImageView alloc]initWithFrame:imageFrame];
[self.userProfilePictureUIImageView设置图像:[UIImage ImageName:@“Placeholder图像”];
[ApplicationUtilities formatViewLayer:self.userProfilePictureUIImageView with BorderRadius:4.0];
//根据图像侧面的长度调整图像内容模式
CGSize avatarSize=self.userProfilePictureUIImageView.image.size;
if(虚拟化宽度<虚拟化高度){
[self.userProfilePictureUIImageView设置内容模式:UIViewContentModeScaleAspectFill];
}否则{
[self.userProfilePictureUIImageView设置内容模式:UIViewContentModeScaleAspectFit];
}
CGFloat readStateSize=10.0;
CGRect readStateFrame=CGRectMake((imageFrame.origin.x+imageFrame.size.width)-readStateSize,CGRectGetMaxY(imageFrame)+4,readStateSize,readStateSize);
//读取状态
self.readStateUIImageView=[[UIImageView alloc]initWithFrame:readStateFrame];
self.readStateUIImageView.backgroundColor=RGBA2UIColor(0.0157.0255.0,1.0);
[ApplicationUtility formatViewLayer:self.readStateUIImageView with borderRadius:readStateSize/2];
sizerFrame.origin.x=CGRectGetMaxX(imageFrame)+kDefaultViewContentHorizontalSpacing;
//仅根据邮件标签的宽度读取发件人标签的宽度
CGRect messageLabelFrame=siz