-
Q:
[cocoa] – vraag over een delegate method
Ik ben bezig cocoa te leren met behulp van het boek “cocoa programming for Mac OSX (3rd edition) door Aaron Hillegass, en stuit op een functie die niet lijkt te werken.
Nou begin ik al aardig wegwijs te raken, en heb met behulp van bindings een tableView gemaakt die data op basis van een zelfgedefinieerde class invoegt, verwijderd, edit.. dat werkt allemaal prima.
Nou wil Hillegass graag dat je ook leert om het op de “oude manier” te doen. Of te wel, de Interface builder met rust laten en met code het zelfde programma werkend te krijgen.
Dat is me gelukt op 1 functie na: sorteren.
Als ik de documentatie erop na sla schijn ik onderstaande methode te moeten gebruiken:
[code:1:bbe72281ea]
– (void)tableView:(NSTableView *)aTableView
sortDescriptorsDidChange:(NSArray *)oldDescriptors
{
NSLog(@"Sort method wordt aangesproken");
NSArray *newDescriptors = [aTableView sortDescriptors];
[employees sortUsingDescriptors:newDescriptors];
[tableView reloadData];
}
[/code:1:bbe72281ea]
Mijn overige datasource methodes zien er vergelijkbaar uit, ik zie niet goed waarom deze genegeerd wordt. Er wordt niet gesorteerd wanneer ik op een header van de tableView klik, en de functie wordt niet aangeroepen.Nou heb ik als oplossing gewoon toch in Interface Building de “Sort Key” en de “Selector” ingevuld van de column die ik wil sorteren, en dat werkt prima natuurlijk. Maar – gewoon uit niewsgierigheid – waarom wordt mijn sort methode niet aangesproken. het is toch een datasource method? De overige datasource methods zoals onderstaande werken wel gewoon:
[code:1:bbe72281ea]
– (void)tableView:(NSTableView *)aTableView
setObjectValue:(id)anObject
forTableColumn:(NSTableColumn *)aTableColumn
row:(int)rowIndex
{
NSString *identifier = [aTableColumn identifier];
Person *person = [employees objectAtIndex:rowIndex];//Set the value for the attribute named identifier
[person setValue:anObject forKey:identifier];
}
[/code:1:bbe72281ea]Alvast bedankt!
Ik begrijp dat die delegate (sortDescriptorsDidChange) niet aangeroepen wordt?
Wat ik her en der lees is dat als de TableView geen selectie of reordering van de columns toestaat, een ‘click’ op de header niet doorgegeven wordt.
Probeer (ergens in de initialisatie, bijv awakeFromNib) het volgende:
[code:1:591aef80be][<tableview object> setAllowsColumnSelection:YES];[/code:1:591aef80be]Hoop dat het helpt.
Leek een goede oplossing maar helaas, dat maakt geen enkel verschil.
Als ik op de header van het column druk zie ik wel dat de datasource methods worden getriggered, maar die sortDiscriptorsDidChange: worden toch genegeerd..
Heb je nog een andere suggestie?
Inderdaad…
Ik denk dat ik er nu wel achter ben:
[code:1:b93df2a187]- (void)tableView:(NSTableView *)aTableView
sortDescriptorsDidChange:(NSArray *)oldDescriptors[/code:1:b93df2a187]Is alleen een delegate die aangeroepen wordt als de sortdescriptors veranderd (zouden kunnen) zijn.
Ik vermoed dat we die dus expliciet moeten triggeren.
We willen de tabel sorteren op geleide van de column header dus we implementeren de delegate die een click op een header van een tabelkolom registreert:
[code:1:b93df2a187]- (void)tableView:(NSTableView *)tableView didClickTableColumn:(NSTableColumn *)tableColumn[/code:1:b93df2a187]
In deze delegate maken we een nieuwe sort descriptor voor onze tabel en maken dit de nieuwe sort descriptor van onze tabel. Middels tableColumn weten we welke header is aangeklikt.
NSTableView heeft de volgende method om een nieuwe sort descriptor aan te geven:[code:1:b93df2a187]- (void)setSortDescriptors:(NSArray *)array[/code:1:b93df2a187]
Als de key value coding magie werkt zou automatisch de delegate sortDescriptorsDidChange aangeroepen moeten worden, zo niet dan doe je het handmatig met
[code:1:b93df2a187][<TableView object> sortDescriptorsDidChange:nil];[/code:1:b93df2a187]
De oude sortdescriptors zijn voor dit voorbeeld toch niet van belang dus kunnen we nil teruggeven als oude SortDescriptor.
Anders kun je in de didClickTableColumn delegate eerst de oude descriptor ophalen met[code:1:b93df2a187]NSArray *oldDescriptors = [<tableView Object> sortDescriptors];[/code:1:b93df2a187]
En die later meegeven.
In je tabel initialisatie moet je wel ergens de eerste keer een sortDescriptor instellen anders is de tabel pas gesorteerd als de gebruiker een eerste keer op een tabel header klikt.Overigens:
[code:1:b93df2a187][<array> sortUsingDescriptors:(NSArray *)<NSSortDescriptor>];[/code:1:b93df2a187]
werkt alleen met een NSMutableArray.Als je me de code PM’t kan ik er thuis ook zelf nog even naar kijken. Automatisch de boel laten sorteren met InterfaceBuilder is wel een stuk eenvoudiger
Fantastisch, hartelijk dank voor je uitgebreide antwoord! Ik ga er vanavond weer even lekker mee stoeien.
’t is inderdaad honderd keer makkelijker in de interface builder, maar het handwerk leert je het best hoe het in z’n werk gaat. Vergeet ik het ook minder snel weer.
Nogmaals heel erg bedankt voor al je tijd en energie!
Ik krijg het nog niet werkend, maar ik moet ook bekennen dat ik niet goed snap wat er nu gebeurd.
In de interface builder kun je een “selector” aangeven en een “Sort Key”. Met de selector geef je de actie aan (toch?) en dat kan dan bijvoorbeeld de methode compare: zijn, en bij de Sort Key geef ik aan welke attribute er gesorteerd moet worden. Hoe ik dat naar code vertaal is me niet goed duidelijk.
Hieronder quote ik een passage uit het boek van Aaron Hillegass, hij legt het als volgt uit:
“The information that you added to the columns of the table is packed into an array of NSSortDescriptor object. A sort descriptor includes the key, a selector, and an indicator of wheteher data should be sorted into ascending or descending order. If you have an NSMutableArray of objects, you can use the following method to sort it:
[code:1:b6b076dae4] – (void)sortUsingDescriptors:(NSArray *)sortDescriptors[/code:1:b6b076dae4]An optional table view dataSource method is triggered when the user clicks the header of a column with a sort descriptor:
[code:1:b6b076dae4]-(void)tableView:(NSTableView *)tableView
sortDescriptorsDidChange:(NSArray *)oldDescriptors[/code:1:b6b076dae4]Thus, if you have a mutable array that holds the information for a table view, you can implement the method like this:
[code:1:b6b076dae4]- (void)tableView:(NSTableView *)tableView
sortDescriptorsDidChange:(NSArray *)oldDescriptors
{
NSArray *newDescriptors = [tableView sortDescriptors];
[myArray sortUsingDescriptors:newDescriptors];
[tableView reloadData];
}
[/code:1:b6b076dae4]=========
Ik zie nergens een methode die de Sort Key en / of selector toewijst. Het lijkt of bovenstaande code helemaal geen verandering te weeg brengt.Volgens bovenstaande claim zou je “didClickTableColumn” zelfs kunnen weglaten, wanneer de “sortUsingDescriptors” methode is gebruikt. Ik kom er met de helpfile niet uit hoe ik die gebruik. Kun je me uitleggen hoe dat werkt?
In je eerste post geef je aan om het allemaal zonder interface builder te willen doen.
Als je een NSTableView object maakt dan moet je (zonder Interface Builder) ook alle code schrijven die de TableView functionaliteit geven.
NSTableView heeft een datasource (bijvoorbeeld zoals in het beschreven voorbeeld uit het boek) en een delegate (ook net als in het boek).
Interface Builder kan automatisch een deel van de code voor zijn rekening nemen. Als je het zonder interface builder wilt doen moet je natuurlijk zelf alle code schrijven.
1. Je wilt dat de tabel sorteert afhankelijk van de header die de gebruiker aanklikt. Dat doe je door de delegate – (void)tableView:(NSTableView *)tableView didClickTableColumn:(NSTableColumn *)tableColumn te implementeren. Hierin maak je een nieuwe sortDescriptor afhankelijjk van welke column er aangeklikt is. Vervolgens sorteer je je NSMutableArray met die sortDescriptor. Daarna laat je de tableview de data opnieuw laden (reloadData) en als het goed is is het dan gesorteerd.
De selectors e.d. in Interface Builder heb je dus niet nodig want je implementeert het allemaal in je eigen code. De geciteerde alinea gaat over sortDescriptors en hoe die gebruikt worden als je alles via Interface Builder doet.
Als je me je je code emailt die je tot dusver hebt kan ik er ook naar kijken.
InactiefAnoniem28 september 2008 om 04:04Ik zou die delegates and datasources gewoon schrappen en gelijk met bindings aan de gang gaan… 8)
Je moet ingelogd zijn om een reactie op dit onderwerp te kunnen geven.