0

我有一个我似乎无法解决的困境。但是,我通过绑定到模型上的属性应用了一些 KVO,因为我没有通过点符号分配 KVO 不会被触发。相反,我像这样附加:

[[self messagesString] appendAttributedString:attrVal];

messagesString是一个NSMutableAttributedString。当然这不会启动 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

我这样做initWithStringNSMutableAttributedString因为如果它还没有空字符串(appendAttributedString如果在实例化时没有设置任何值,则有问题),您使用此类实例的方式会有些奇怪。

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

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

最后,我的 UI 在 Attributed String 属性上有一个绑定,NSTextView可以转到self.currentChannel.messagesString. 我现在不在我的 Mac 上,所以我无法显示这些位。

appendString我班上的方法Channel看起来就像是因为我在玩弄它来让它工作。非常玩代码。

4

1 回答 1

2

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

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

在这一点上,我只能推测你的属性、你的类或你的 observeValueForKeypath: 方法有一些非常不寻常的地方来监视这些变化。

编辑:问题是 NSTextView。它维护自己的存储系统,因此实际上当您想要将数据附加到它时,您将直接执行此操作,并且与您的属性字符串的绑定应该更新(而不是相反)。当您进行最终更改时它起作用的原因是您告诉 textView 字符串已更改,但当它看起来最初并没有更改时,但最终当您确实设置了一个全新的字符串时,它会注册更改并更新。

看看这个线程的推理和解决方案。戴维森是长期负责文本系统的苹果工程师之一(他回答了这个问题)。

于 2012-08-04T12:11:54.110 回答