Wie ein Objekt an einen programmatisch gebunden NSMutableArray hinzufügen?
-
09-09-2019 - |
Frage
Ich habe eine NSDocument, die die folgende Struktur:
@interface MyDocument : NSDocument
{
NSMutableArray *myArray;
IBOutlet NSArrayController *myArrayController;
IBOutlet MyView *myView;
}
@end
instanziiert ich die NSArrayController und die MyView in MyDocument.xib, und haben die Verbindungen zu den Datei-Besitzer (MyDocument) gemacht, so dass ich bin mir ziemlich sicher, dass aus der Sicht von Interface Builder, ich alles richtig gemacht haben.
Die Schnittstelle für MyView ist einfach:
@interface MyView : NSView {
NSMutableArray *myViewArray;
}
@end
Nun, in MyDocument windowControllerDidLoadNib
, ich habe den folgenden Code:
- (void)windowControllerDidLoadNib:(NSWindowController *) aController
{
[super windowControllerDidLoadNib:aController];
[myArrayController setContent:myArray];
// (This is another way to do it) [myArrayController bind:@"contentArray" toObject:self withKeyPath:@"myArray" options:nil];
[myView bind:@"myViewArray" toObject:myArrayController withKeyPath:@"arrangedObjects" options:nil];
}
Im Debugger Ich habe festgestellt, dass myViewArray
ist ein NSControllerArrayProxy, so scheint es, dass meine programmatische Bindung korrekt ist. Allerdings, wenn ich versuche, Objekte in MyView Methoden zum MyView myViewArray
hinzufügen, erscheinen sie nicht die MyDocument des myArray
zu aktualisieren. Ich habe die beiden folgenden Ansätze versucht:
[myViewArray addObject:value];
[self addMyViewArraysObject:value];
(Der zweite Ansatz führt zu einem Compiler-Fehler, wie erwartet, aber ich dachte, dass die Objective-C-Laufzeit würde „implementieren“ diese Methode pro meinem begrenzten Verständnis von KVO).
Gibt es etwas falsch mit, wie ich versuche, myViewArray
zu aktualisieren? Gibt es etwas falsch mit meiner programmatischen Bindung? (Ich versuche, dies programmatisch zu tun, weil MyView eine benutzerdefinierte Ansicht ist, und ich möchte nicht eine IB-Palette für sie schaffen.)
Lösung
Das Problem ist, dass Sie Ihre Array direkt sind mutiert. Implementieren Sie indiziert Accessormethoden und diejenigen nennen.
KVO überschreibt Ihre Zugriffsmethoden (solange Sie bestimmte Formate ) und die notwendigen Meldungen postet. Sie haben nicht das bekommen, wenn Sie direkt zu Ihrem Array sprechen; alles auf die Eigenschaft gebunden werden nicht wissen, dass Sie die Eigenschaft geändert haben, wenn Sie es ausdrücklich sagen. Wenn Sie Ihre Zugriffsmethoden verwenden, sagt KVO die anderen Objekte für Sie.
Die einzige Zeit, nicht Ihre Accessormethoden (synthetisiert oder auf andere Weise) zu verwenden ist in init
und dealloc
, da Sie zu einem Halb init
ed oder -dealloc
ked Objekt würde sprechen.
Wenn Sie Ihre eigene Zugriffsmethoden verwenden das Array zu mutieren und dadurch bekommen die freien KVO-Benachrichtigungen, die Dinge sollten einfach funktionieren:
- Die Aussicht, wenn seine Eigenschaft mutiert, wird die Array-Controller automatisch benachrichtigt, die ihre
content
Eigenschaft mutiert, die den Controller benachrichtigt. - Ihr Controller, wenn seine Eigenschaft mutiert, wird die Array-Controller automatisch benachrichtigt, die ihre
arrangedObjects
Eigenschaft mutiert, die die Ansicht teilt.
Andere Tipps
Ich kann zwei Möglichkeiten sehen Sie hier:
Zuerst geht instanziert das NSMutableArray
Objekt (und loslassen) in Ihrer MyDocument
Klasse? Es soll wie folgt aussehen:
- (id)init
{
if ((self = [super init]) == nil) { return nil; }
myArray = [[NSMutableArray alloc] initWithCapacity:0];
return self;
}
- (void)dealloc
{
[myArray release];
[super dealloc];
}
Zweitens habe erklären Sie myViewArray als Eigenschaft in MyView
? Es soll wie folgt aussehen:
// MyView.h:
@interface MyView : NSView
{
NSMutableArray * myViewArray;
}
@property (assign) NSMutableArray * myViewArray;
@end
// MyView.m:
@implementation MyView
@synthesize myViewArray;
@end
Other than that, es sieht für mich wie Sie alle die Bindung richtig gemacht haben.
Update: Wie über den NSArrayController
mit Artikel zum Array hinzuzufügen:
// MyView.h:
@interface MyView : NSView
{
NSMutableArray * myViewArray;
IBOutlet NSArrayController * arrayController;
}
@property (assign) NSMutableArray * myViewArray;
- (void)someMethod;
@end
// MyView.m:
@implementation MyView
@synthesize myViewArray;
- (void)someMethod
{
id someObject = [[SomeClass alloc] init];
[arrayController addObject:[someObject autorelease]];
}
@end
Das Problem scheint zu sein, dass ich hatte MyView die myViewArray
auf die NSArrayController des arrangedObjects
Eigenschaft für verbindlich statt dessen content
Eigenschaft.
Wenn arrangedObjects
Bindung, fand ich, dass das eigentliche Objekt, auf dem durch myViewArray
war eine Instanz von NSControllerArrayProxy
. Ich habe keine definitive Antwort auf die Frage finden, was das Objekt tatsächlich tut, wenn ich auf sie online mehr Informationen gesucht. Allerdings deuten die Code-Beispiele Ich fand, dass NSControllerArrayProxy sollte an Komfort belichten für den Zugriff auf die Eigenschaften von Objekten im Array , anstatt die Objekte (im Array) selbst. Aus diesem Grunde glaube ich, dass ich mich geirrt bei der Bindung an arrangedObjects
.
Die Lösung wurde auf statt MyView des myViewArray
auf die die NSArrayController binden content
Eigenschaft:
- (void)windowControllerDidLoadNib:(NSWindowController *) aController
{
[super windowControllerDidLoadNib:aController];
[myArrayController setContent:myArray];
[myView bind:@"myViewArray" toObject:myArrayController withKeyPath:@"content" options:nil];
}
Obwohl dies scheint zu funktionieren, ich bin nicht 100% sicher, dass es richtig ist, zu binden content
in diesem Fall. Wenn jemand kann etwas Licht auf programmatisch auf die verschiedenen Eigenschaften eines NSArrayController Bindung, würde ich Kommentare zu dieser Antwort begrüßen. Danke.
Zunächst einmal gibt es nichts falsch mit der Bindung an arrangedObjects: ein NSTableColumn, zum Beispiel, sollte sein Gehalt an arrangedObjects nur gebunden hat, und ihre content zu arrangedObjects.someProperty.
Der häufigste Fehler ist arrangedObjects als Inhalt eines Arraycontroller zu betrachten, sondern dass, wie Sie, zu Trauer gesehen haben führen: arrangedObjects eine Darstellung der Art und Weise ist der Arraycontroller zur Zeit die Objekte in ihrem Inhalt angeordnet hat, nicht den Inhalt selbst.
Das heißt, die Art und Weise um ein Array zu einem Arraycontroller zu binden:
[self.myArrayController bind:NSContentArrayBinding
toObject:self
withKeyPath:@"myView.myViewArray"
options:nil];
Sind Sie sicher, nebenbei gesagt, Ihrer Ansicht nach braucht die myViewArray zu halten? Das in der Regel fällt unter der Verantwortung eines Controllers oder Modellobjekt.
Jetzt können Sie Objekte hinzufügen, indem Aufruf addObject auf dem Arraycontroller , denn das ist in der Verantwortung des Controllers ist.
[self.myArrayController addObject: anObject]