Sie können einen benutzerdefinierten Vergleicher verwenden.
Um die Grundidee dieses Ansatzes zu demonstrieren, nehmen wir an, dass Sie NSTreeNode
als Ihre Baumknotenklasse verwenden. Alle Wurzelknoten werden in einer NSArray
namens gespeichert content
und Ihre drei Wurzelknoten sind cat
, dog
und fish
:
NSTreeNode *cat = [NSTreeNode treeNodeWithRepresentedObject:@"cat"];
// ...the same for dog and fish
self.content = @[cat, dog, fish];
Dann erstellen Sie Ihre NSSortDescriptor
Prototyp. Beachten Sie, dass Sie anstelle des zu vergleichenden Strings self
als Schlüssel verwenden sollten (in diesem Fall representedObject
), um Zugriff auf das rohe Knotenobjekt zu erhalten. Überprüfen Sie im Vergleich, ob das Objekt in Ihrem Root-Objekt-Array enthalten ist. Wenn YES
, geben Sie einfach NSOrderedSame
zurück, da es die Reihenfolge von der ursprünglichen Reihenfolge in Ihrem Array content
unverändert lässt, andernfalls verwenden Sie die compare:
Methode, um einen Standardvergleich durchzuführen.
NSSortDescriptor *sortDescriptor = [NSSortDescriptor sortDescriptorWithKey:@"self" ascending:YES comparator:^NSComparisonResult(NSTreeNode *obj1, NSTreeNode *obj2) {
if ([self.content containsObject:obj1] && [self.content containsObject:obj2]) {
return NSOrderedSame;
}
return [obj1.representedObject compare:obj2.representedObject];
}];
[[outlineView.tableColumns firstObject] setSortDescriptorPrototype:sortDescriptor];
Edit 2
Wenn Sie mehrere Spalten haben, die separat sortiert werden müssen, können Sie nicht für jede Spalte self
als Schlüssel verwenden, da der Schlüssel unter allen Spalten eindeutig sein sollte 'sortDescriptorPrototype
s. In diesem Fall können Sie ein benutzerdefiniertes Objekt als representedObject
erstellen und alle Ihre Daten einschließlich eines Zeigers zurück auf den Baumknoten im Objekt übertragen.
Edit 1
Die Richtigkeit des Ansatzes oben genannten erfordert NSOutlineView
seine Reihen mit einem stabilen Art Algorithmus zu sortieren. Das heißt, identische Artikel behalten immer die gleiche relative Reihenfolge vor und nach dem Sortieren. Allerdings konnte ich in der Apple-Dokumentation keinen Hinweis auf die Stabilität des hier verwendeten Sortieralgorithmus finden, obwohl meiner Erfahrung nach der obige Ansatz tatsächlich funktionieren wird.
Wenn Sie sich unsicher fühlen, können Sie Ihre Stammbaumknoten explizit vergleichen, je nachdem, ob die aktuelle Reihenfolge aufsteigend oder absteigend ist. Dazu benötigen Sie eine ivar
, um die aktuelle Bestellung zu speichern.Nur Umsetzung der outlineView:sortDescriptorsDidChange:
Delegatmethode:
- (BOOL)outlineView:(NSOutlineView *)outlineView sortDescriptorsDidChange:(NSArray *)oldDescriptors {
ascending = ![oldDescriptors.firstObject ascending];
return YES;
}
Und return NSOrderedSame
ändern:
if ([self.content containsObject:obj1] && [self.content containsObject:obj2]) {
NSUInteger index1 = [self.content indexOfObject:obj1];
NSUInteger index2 = [self.content indexOfObject:obj2];
if (ascending)
return (index1 < index2) ? NSOrderedAscending : NSOrderedDescending;
else
return (index1 < index2) ? NSOrderedDescending : NSOrderedAscending;
}
bearbeiten 3
Wenn Sie nicht outlineView:sortDescriptorsDidChange:
aus irgendeinem Grund implementieren können, können Sie manuell einen Beobachter heften sich an Das sortDescriptors-Array von outlineView:
[outlineView addObserver:self forKeyPath:@"sortDescriptors" options:NSKeyValueObservingOptionNew context:nil];
Auf diese Weise können Sie benachrichtigt werden, wenn der Benutzer auch auf die Kopfzeile klickt. Danach nicht vergessen, die folgenden Beobachtungsverfahren, als ein Teil der KVO Prozess zu implementieren:
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context {
if ([keyPath isEqualToString:@"sortDescriptors"]) {
// Again, as a simple demonstration, the following line of code only deals with the first sort descriptor. You should modify it to suit your need.
ascending = [[change[NSKeyValueChangeNewKey] firstObject] ascending];
}
}
Speicher undicht zu verhindern, müssen Sie diese Beobachter entfernen, bevor outlineView
freigegeben wird (wenn nicht früher). Wenn Sie mit KVO nicht vertraut sind, überprüfen Sie bitte .
Haben Sie versucht, den benutzerdefinierten 'sortDescriptorPrototype 'der NSTableColumn-Instanz festzulegen, auf die Sie klicken? – Astoria
@Astoria Ja! Ich habe das ausprobiert, und es funktionierte für diese Spalte (mit den Daten von den Elternknoten). Aber die Kinderknoten haben Daten in anderen Spalten, und es sollte möglich sein, die Kinder durch Klicken auf solche Spaltenköpfe zu sortieren. Wenn Sie jedoch auf solche Spalten klicken, wirkt sich dies auch auf die Reihenfolge der übergeordneten Knoten aus. – aneuryzm
versuchen, 'sortDescriptorPrototype' für beide Spalten zu setzen. – Astoria