0

Ich habe ein Fenster mit einem NSTextField (in Snow Leopard), das ich an eine NSString-Funktion in meiner WindowController-Klasse gebunden habe. Diese Zeichenfolge kombiniert Informationen über die Auswahl und Zählung meiner Tabellenansicht, die von meinem Array-Controller bereitgestellt werden. Es erhält einen Anfangswert, "0 0", wird jedoch nie aktualisiert, wenn sich die Auswahl oder die Anzahl ändert. Die Bindung sieht wie folgt aus (Datei-Besitzer ist MyWindowController):Warum sind meine Cocoa-Bindungen gebrochen?

alt text

I umgesetzt + (NSSet *)keyPathsForValuesAffecting<key> (siehe unten), aber die Bindung nie Updates, auch wenn die Gesamtzahl und Auswahl Änderung der Array-Controller.

(Zusätzliche Fehlerbehebung durchgeführt) Ich hatte ursprünglich die Display Pattern Value Bindung des NSTextField verwendet, aber ich brauchte kompliziertere Logik als diese Bindung geboten. Ich habe dann angefangen, die Auswahl zu lesen, die Ereignisse des TableView geändert/geändert hat, die den Inhalt des Array-Controllers anzeigt und die Display Pattern Value-Bindungen dynamisch ändert, aber das fühlte sich wie ein Hack an und war zu kompliziert.

Ich bin mir sicher, dass ich etwas vermisse, aber ich kann nicht sagen, was. Hat jemand irgendwelche Ideen? Ich habe die Dokumentation von Key-Value-Observing von Apple gelesen, und das scheint alles zu sein, was nötig ist. Ich habe überprüft, und meine keyPathsForValuesAffectingMyString wird aufgerufen, aber myString wird nur einmal aufgerufen. Ich habe meinen Code unten destilliert (aktualisiert x3).

aktualisieren 1/21

Ich versuche immer noch Einstecken entfernt, dies herauszufinden. Wenn ich addObserver bis self für die ArrayController-Schlüsselpfade, die Benachrichtigungen ausgelöst werden, wie erwartet, so ist meine Schlüsselpfade und der Schlüsselwert Beobachtungsmechanismus in Ordnung. Wenn ich [self didChangeValueForKey:@"myString"]; innerhalb meiner observeValueForKeyPath-Methode für die gleichen Schlüssel aufrufen, wird die Bindung immer noch nicht aktualisiert, was zu der Annahme führt, dass es sich eher um ein Bindungsproblem als um ein KVO-Problem handelt. Ich werde mehr auf die Bindungen Mechanismus zu lesen up ...

@interface MyWindowController : NSWindowController { 
    IBOutlet NSArrayController *arrayController; 
} 

- (NSArrayController *)arrayController; 
- (NSString *)myString; 

@end 

@implementation MyWindowController 

+ (NSSet *)keyPathsForValuesAffectingMyString { 
    return [NSSet setWithObjects: 
      @"arrayController.arrangedObjects", 
      @"arrayController.selection", 
      nil]; 
} 

- (NSArrayController *)arrayController { 
    return arrayController; 
} 

- (NSString *)myString { 
    // Just as an example; I have more complicated logic going on in my real code 
    return [NSString stringWithFormat:@"%@, %@", 
      [arrayController valueForKeyPath:@"[email protected]"], 
      [arrayController valueForKeyPath:@"[email protected]"]]; 
} 

@end 
+0

Sind Sie auf Mac OS 10.5 ausgerichtet? –

+0

10.6, Snow Leopard, und ich bin nicht besorgt über die Rückwärtskompatibilität. – Dov

+0

Setzen Sie einen Haltepunkt auf "-arrayController" und starten Sie Ihre App. Die ersten Male, die es genannt wird, was ist der Wert von 'arrayController?' –

Antwort

0

Vergewissern Sie sich, dass die arrayController Steckdose im Interface Builder verbunden ist. Ich vermute, dass es nichts ist.

+0

Es ist definitiv verbunden, und ich benutze es überall. – Dov

0

Verwenden Sie nicht das Schlüsselwort @count. Bindungen und KVO auf Array-Controllern werden aktualisiert, wenn sich der Inhalt ändert. Wenn das nicht funktioniert, gibt es irgendwo anders ein Problem.

Eine weitere Option besteht darin, die Anzeigemusterbindungen anstelle einer zusammengesetzten Eigenschaft zu verwenden. Bindet Display Pattern Value1 an arrayController.arrangedObjects. @ Count und Display Pattern Value2 an arrayController.selection. @ Count, und setze das Muster auf "% {value1} @,% {value2} @"

+0

Ich habe es ohne das @ count-Schlüsselwort versucht (und habe meinen Code oben aktualisiert), ohne das Ergebnis zu ändern. Ich habe ursprünglich die Bindestriche des Displaymusters verwendet, möchte jedoch von diesem Abstand abweichen, um feinere Steuerelemente und kompliziertere Ausdrücke zu erhalten. – Dov

1

Ich habe eine Workaround, aber ich bin nicht glücklich darüber, da es nicht notwendig sein sollte, und ich würde immer noch bevorzugen, die Bindungen richtig zu funktionieren. Ich werde diese Antwort nicht akzeptieren und lösche sie, wenn jemand einen tatsächlichen Fix veröffentlicht. </disclaimer>

@interface MyWindowController : NSWindowController { 
    IBOutlet NSArrayController *arrayController; 
    IBOutlet NSTextField *fieldThatShouldBeBinded; 
} 

- (NSString *)myString; 

@end 

@implementation MyWindowController 

- (void)awakeFromNib { 
    [arrayController addObserver:self 
         forKeyPath:@"selection" 
         options:0 
         context:NULL]; 
    [arrayController addObserver:self 
         forKeyPath:@"arrangedObjects" 
         options:0 
         context:NULL]; 
} 

- (void)observeValueForKeyPath:(NSString *)keyPath 
         ofObject:(id)object 
         change:(NSDictionary *)change 
         context:(void *)context { 
    if(object == arrayController) 
     [fieldThatShouldBeBinded setStringValue:[self myString]]; 
} 

- (NSString *)myString { 
    return [NSString stringWithFormat:@"%@, %@", 
      [arrayController valueForKeyPath:@"[email protected]"], 
      [arrayController valueForKeyPath:@"[email protected]"]]; 
} 

@end 
0

Ich traf das gleiche Problem und fand einen anderen Weg (aber es ist immer noch Umgehungsmöglichkeit). Sie müssen eine dynamische Workaround-Eigenschaft deklarieren. Übergeben Sie im Implementierungsabschnitt einfach ein neues leeres Objekt dafür. Jetzt können Sie diese Problemumgehungseigenschaft KVO.

@property(nonatomic,retain) NSArray *workaround; 
@dynamic workaround; 
- (NSArray *)workaround { return [NSArray array]; } // new *every* time 
- (void)setWorkaround:(NSArray *)unused { } 

+ (NSSet *)keyPathsForValuesAffectingMyString { return [NSSet setWithObject:@"workaround"]; } 

diese Arbeit zu bekommen, müssen Sie noch manuell self.workaround zu arrayController.selectedObjects (oder was auch immer) binden:

- (void)awakeFromNib // or similar place 
{ 
    [super awakeFromNib]; 
    [self bind:@"workaround" toObject:arrayController withKeyPath:@"selectedObjects" options:nil]; 
} 

Manuelle Bindung funktioniert wie erwartet, wird Abhilfe aktualisiert mit dem, was Sie verpflichtet haben, es zu. Aber KVO prüft, ob der Eigenschaftswert tatsächlich geändert wird (und hört auf, sich zu verbreiten, wenn er gleich ist). Wenn Sie jedes Mal den neuen Wert self.workaround zurückgeben, funktioniert es.

Warnung: nie Anruf -[setWorkaround:] selbst - das wird die andere Seite der Bindung (arrayController.selectedObjects in diesem Fall) effektiv spülen.

Diese Methode hat einige Vorteile: Sie zentralisierte observeValueForKeyPath vermeiden: ... und Ihre Logik ist an der richtigen Stelle. Und es skaliert gut, fügen Sie einfach Workaround2, 3 usw. für ähnliche Fälle hinzu.

+0

Und wenn Sie immer noch addObserver: Methode verwenden, vergessen Sie nicht, entsprechende removeObserver: in Dealloc aufzurufen. –

Verwandte Themen