2012-08-03 2 views
0

J'ai un dilemme que je n'arrive pas à résoudre. J'ai appliqué un certain KVO par une liaison à une propriété sur un modèle, cependant, parce que je n'assigne pas par la notation de point le KVO ne se fait pas virer. Au lieu de cela, je suis donc comme AJOUT DE:NSMutableAttributedString Notification de non-déclenchement KVO

[[self messagesString] appendAttributedString:attrVal]; 

messagesString est un NSMutableAttributedString. Bien sûr, cela ne déclenchera pas la notification KVO, donc je fais ce qui suit:

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

Mais je n'ai pas de chance avec ça. Si je fais ce qui suit:

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

Ensuite, cela fonctionne très bien. Cependant, si je supprime la ligne d'ajout, cela ne fonctionne pas. Il semble que ce soit dans cet ordre, y compris ces choses, pour que cela fonctionne.

Qu'est-ce qui me manque si évident pour lancer la notification du KVO?

EDIT

Alors, je l'ai arraché toute substance non pertinente de cette déclaration de classe, mais voici la principale dont je parlais:

#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 

Et la mise en œuvre

#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 

Je fais initWithString pour le NSMutableAttributedString car il y a quelques bizarreries dans la façon dont vous utilisez un i nstance de cette classe si elle n'a pas déjà une chaîne vide (appendAttributedString a des problèmes si aucune valeur n'a été définie lors de l'instanciation soi-disant).

Voilà comment une chaîne est ajoutée à elle dans une classe à part entière:

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

Enfin, mon interface utilisateur a une liaison pour un NSTextView sur la propriété Chaîne Attribuée pour aller à self.currentChannel.messagesString. Je ne suis pas sur mon Mac pour le moment, donc je ne peux pas montrer ces morceaux.

La méthode appendString dans ma classe Channel a l'air d'être comme ça parce que je travaillais pour la faire fonctionner. Beaucoup de code de jeu.

+0

Quelle est la déclaration de propriété de messageString? –

+0

Pouvez-vous poster votre appel d'installation d'observation et la méthode de surveillance des changements? –

+0

@BrianPalma mon post mis à jour montre ceci. – Kezzer

Répondre

2

J'ai créé un projet et joué avec. Si vous décidez d'utiliser KVO manuel (en utilisant la déclaration de méthode de classe ...), vous n'obtiendrez pas kvo lorsque vous utiliserez "setValue" sur cette propriété ivar/(donc ma réponse d'origine n'était pas correcte).

J'ai créé un projet de test, puis utilisé une chaîne mutable et vérifié que oui, j'ai reçu KVO quand j'ai utilisé les messages will/did enroulés autour d'un appendString: à la chaîne mutable. Cela a vérifié que le code que vous montrez devrait en fait fonctionner. J'ai ensuite commenté ce code et directement définir la chaîne mutable avec une autre chaîne et n'a pas du tout KVO (comme prévu). À ce stade, je ne peux que supposer qu'il y a quelque chose de très inhabituel à propos de votre propriété, de votre classe ou de votre méthode observeValueForKeypath: pour surveiller ces changements.

EDIT: Le problème est NSTextView.Il maintient son propre système de stockage, donc quand vous voulez ajouter des données, vous le faites directement, et la liaison à VOTRE attributeString devrait être mise à jour (pas l'inverse). La raison pour laquelle cela a fonctionné quand vous avez fait ce changement final, c'est que vous avez dit à textView que la chaîne avait changé, mais quand elle a changé, elle a enregistré la modification et a été mise à jour. Regardez ce thread pour le raisonnement et la solution. Davidson est l'un des ingénieurs d'Apple depuis longtemps responsables du système de texte (il a répondu à la question).

+0

Sûrement la mise en œuvre par défaut traite de cela? Il y a une foule de documents indiquant que vous appelez simplement willChange/didChange et que cela avertira les observateurs de la modification apportée à l'instance. – Kezzer

+0

Ceci est très utile. Permettez-moi de saisir le code dont vous aurez besoin pour déchiffrer cela. Je suppose que je fais quelque chose de très mauvais, mais cela ne me surprend pas. – Kezzer

+0

J'ai mis à jour mon message pour refléter ce dont vous pourriez avoir besoin. Je ne sais toujours pas ce que je fais de mal. Je pense que ce sont les attributs de ma déclaration de propriété qui sont faux. C'est une question de savoir si KVO est configuré correctement. Comme décrit dans la publication, je lie sur Attributed String pour le NSTextView qui peut être un facteur. – Kezzer

Questions connexes