NSMutableAttributedString KVO未触发通知

时间:2012-08-03 19:57:19

标签: objective-c key-value-observing

我遇到了一个我似乎无法解决的困境。我通过绑定到模型上的属性来应用一些KVO,但是,因为我没有通过点表示法分配KVO不被解雇。相反,我是这样追加的:

[[self messagesString] appendAttributedString:attrVal];

messagesStringNSMutableAttributedString。当然,这不会启动KVO通知,所以我做了以下事情:

[self willChangeValueForKey:@"messagesString"];
[[self messagesString] appendAttributedString:attrVal];
[self didChangeValueForKey:@"messagesString"];

但我对此没有运气。如果我执行以下操作:

NSAttributedString *attrVal = [[NSAttributedString alloc] initWithString:str];
[self willChangeValueForKey:@"messagesString"];
[[self messagesString] appendAttributedString:attrVal];
[self didChangeValueForKey:@"messagesString"];
messagesString = [[NSMutableAttributedString alloc] initWithAttributedString:messagesString];

然后它工作正常。但是,如果我删除附加行,则它不起作用。它似乎必须按照这个顺序,包括这些东西,才能发挥作用。

我错过了什么让它开始KVO通知显而易见?

修改

所以,我已经从这个类声明中删除了任何不相关的东西,但这是我所指的主要内容:

#import <Foundation/Foundation.h>

@interface Channel : NSObject {
    NSString* name;
    NSMutableAttributedString *messagesString;
}

@property (retain) NSString* name;
@property (retain) NSMutableAttributedString* messagesString;

- (id)initWithName:(NSString*)name;
- (void)appendString:(NSString*)str;

@end

实施

#import "Channel.h"

@implementation Channel

@synthesize name;
@synthesize messagesString;

- (id)initWithName:(NSString *)channelName {
    self = [super init];

    if (self)
    {
        [self setName:channelName];
        messagesString = [[NSMutableAttributedString alloc] initWithString:@" "];
    }

    return self;
}


- (void)appendString:(NSString *)str {
     NSAttributedString *attrVal = [[NSAttributedString alloc] initWithString:str];
    [self willChangeValueForKey:@"messagesString"];
    [[self messagesString] appendAttributedString:attrVal];
    [self didChangeValueForKey:@"messagesString"];
    messagesString = [[NSMutableAttributedString alloc] initWithAttributedString:messagesString];
}

@end

我为initWithString做了NSMutableAttributedString因为如果它没有空字符串,那么你使用这个类的实例的方式有些奇怪(appendAttributedString有问题,如果在假设实例化时没有设置任何值。)

这是在完全独立的类中将字符串附加到它的方式:

Channel *c = [channels valueForKey:@"server"];
[c appendString:val];

最后,我的UI在Attributed String属性上绑定了NSTextView以转到self.currentChannel.messagesString。我现在不在Mac上,所以我无法展示这些内容。

我的appendString课程中的Channel方法看起来就像是因为我正在努力让它运转起来。很多游戏代码。

1 个答案:

答案 0 :(得分:2)

我创建了一个项目并玩弄它。如果您决定使用手动KVO(使用自动...类方法声明),那么当您在该ivar / property上使用“setValue”时,您将无法获得kvo(因此我的原始答案不正确)。

我创建了一个测试项目,然后使用了一个可变字符串并验证了是,当我使用包含appendString的will / did消息时,我确实获得了KVO:变量字符串。这证实了您显示的代码实际上应该可以工作。然后我注释掉了代码并直接用另一个字符串设置了可变字符串,并且根本没有获得任何KVO(如预期的那样)。

此时我只能猜测你的财产,你的班级或者观察观察这些变化的observeValueForKeypath:方法有一些非常不寻常的事情。

编辑:问题是NSTextView。它维护自己的存储系统,所以实际上当你想要向它添加数据时,你将直接执行它,并且对你的attributionString的绑定应该更新(而不是相反)。当你做出最后一次更改时它的工作原理是你告诉textView字符串已经改变了,但是看起来它最初没有改变,但最后当你设置了一个全新的字符串时,它注册了更改并更新。

对于推理和解决方案,请查看此thread。 Davidson是Apple长期负责文本系统的工程师之一(他回答了这个问题)。