2012-08-03 87 views
0

我有两难,我似乎无法解决。我已经通过绑定到模型上的属性来应用一些KVO,但是,因为我没有通过点符号分配,所以KVO不会被解雇。相反,我追加像这样:NSMutableAttributedString 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 

我做initWithStringNSMutableAttributedString,因为你有一些古怪的方式,你使用我这个类的实例,如果它没有一个空字符串的话(appendAttributedString如果在实例化时没有设置任何值,就会有问题)。

这是一个字符串是如何追加到它在一个完全独立的类:

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

最后,我的UI具有对属性串财产NSTextView绑定去self.currentChannel.messagesString。此刻我不在我的Mac上,所以我无法显示这些位。

在我的Channel类中的appendString方法看起来像是因为我正忙着让它工作。非常多玩代码。

+0

messageString的属性声明是什么? – 2012-08-03 20:23:51

+0

你可以发布你的观察设置调用和观察变化的方法吗? – 2012-08-05 15:29:18

+0

@BrianPalma我更新后的帖子显示了这一点。 – Kezzer 2012-08-06 07:56:02

回答

2

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

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

在这一点上,我只能推测,有关你的财产,你的课程或你的observeValueForKeypath:方法观察这些变化是非常不寻常的。

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

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

+0

当然默认的实现处理这个?有大量文档声明您只需调用willChange/didChange并将通知观察者对实例的更改。 – Kezzer 2012-08-05 07:17:57

+0

这非常有用。让我抓住你需要破译的代码。我假设我做的事情非常错误,但这并不令我感到意外。 – Kezzer 2012-08-06 07:42:15

+0

我已更新我的帖子以反映您可能需要的内容。我仍然不知道我做错了什么。我认为这是属性声明中的属性是错误的。这是KVO是否正确安装的一个案例。正如后文所述,我绑定在NSTextView的Attributed String上,这可能是一个因素。 – Kezzer 2012-08-06 08:03:56