PDA

View Full Version : tableview delegate sortDescriptorsDidChange not getting called




BenCoffman
Sep 5, 2009, 01:50 PM
I'm trying to sort my tableColumn, but the sortDescriptorsDidChange is not getting called

Three other delegate functions are getting called.

- (void)tableView:(NSTableView *)aTableView
setObjectValue:(id)anObject
forTableColumn:(NSTableColumn *)aTableColumn
row:(int)rowIndex

- (id)tableView:(NSTableView * )aTableView
objectValueForTableColumn:(NSTableColumn *)aTableColumn
row:(int)rowIndex

- (int)numberOfRowsInTableView:(NSTableView *)aTableView




All above three get called but the one below does not. I have no idea why.


- (void)tableView:(NSTableView *)tableView sortDescriptorsDidChange:(NSArray *)oldDescriptors



I've set up a breakpoint and it's not even stopping inside the function.

Further here is my exact code.


- (int)numberOfRowsInTableView:(NSTableView *)aTableView
{
return [employees count];
}

- (id)tableView:(NSTableView * )aTableView
objectValueForTableColumn:(NSTableColumn *)aTableColumn
row:(int)rowIndex
{
//What is the identifier for the column?
NSString *identifier = [aTableColumn identifier];

//What person?
Person *person = [employees objectAtIndex:rowIndex];

//What is the value of the attribute named identifier
return [person valueForKey:identifier];
}

- (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];
}

- (void)tableView:(NSTableView *)atableView
sortDescriptorsDidChange:(NSArray *)oldDescriptors
{
NSArray *newDescriptors = [atableView sortDescriptors];
[employees sortUsingDescriptors:newDescriptors];
[tableview reloadData];
}



mdeh
Sep 7, 2009, 01:51 AM
I'm trying to sort my tableColumn, but the sortDescriptorsDidChange is not getting called

All above three get called but the one below does not. I have no idea why.


- (void)tableView: (NSTableView *)tableView sortDescriptorsDidChange: (NSArray *)oldDescriptors

- (void)tableView: (NSTableView *)atableView
sortDescriptorsDidChange: (NSArray *)oldDescriptors


Try your code with the declaration and definition **exactly** the same.

BenCoffman
Sep 7, 2009, 02:15 AM
Try your code with the declaration and definition **exactly** the same.


I changed it to this


- (void)tableView:(NSTableView *)aTableView
sortDescriptorsDidChange:(NSArray *)oldDescriptors


Cleaned targets and rebuilt. No love.

warwick
Sep 7, 2009, 02:39 AM
tableView:sortDescriptorsDidChange: is a 10.6 only method. Are you certain you're building against the 10.6 libraries?

Also, when are you expecting this to be called? I don't see you setting the sortDescriptor at any point.

BenCoffman
Sep 7, 2009, 01:44 PM
tableView:sortDescriptorsDidChange: is a 10.6 only method. Are you certain you're building against the 10.6 libraries?

Also, when are you expecting this to be called? I don't see you setting the sortDescriptor at any point.


Upgrading to 10.6 was a good suggestion, though it did not solve my problem. It however made the very annoying
unable to read unknown load command 0x80000022
error go away.

Unfortunately xcode still does not break in the method during debug and sorting is not working.

I think I set the sortDescriptor in the the method above here it is again for convenience.

NSArray *newDescriptors = [aTableView sortDescriptors];
[employees sortUsingDescriptors:newDescriptors];

warwick
Sep 7, 2009, 04:24 PM
The tableView:sortDescriptorsDidChange: method won't be called unless some other piece of code calls setSortDescriptors: on your tableview.

BenCoffman
Sep 7, 2009, 04:39 PM
The tableView:sortDescriptorsDidChange: method won't be called unless some other piece of code calls setSortDescriptors: on your tableview.

I'm not entirely sure that is correct. Here is what the apple Docs say about this function

Invoked by aTableView to indicate that sorting may need to be done.

- (void)tableView:(NSTableView *)aTableView sortDescriptorsDidChange:(NSArray *)oldDescriptors

Parameters
aTableView
The table view that sent the message.

oldDescriptors
An array that contains the previous descriptors.

Discussion
The data source typically sorts and reloads the data, and adjusts the selections accordingly. If you need to know the current sort descriptors and the data source does not manage them itself, you can get the current sort descriptors by sending aTableView a sortDescriptors message.

Implementation of this method is optional.

http://developer.apple.com/mac/library/documentation/Cocoa/Reference/ApplicationKit/Protocols/NSTableDataSource_Protocol/Reference/Reference.html#//apple_ref/occ/intfm/NSTableViewDataSource/tableView:sortDescriptorsDidChange:

It does not state that setSortDescriptors needs to be called. I could be wrong though. I won't stand behind my answer. :)

yoavcs
Sep 7, 2009, 05:35 PM
You can also invoke that method by clicking on column headers in the UI to cause a sort to happen.

warwick
Sep 7, 2009, 05:37 PM
In Cocoa, there are often datasource or delegate methods that contain phrases like "didChange" or "willChange". These methods are called only when the value they're referring to actually changes.

The method we're looking at here, tableView:sortDescriptorsDidChange: is a method of this type. The name of the method implies that it will be called after the sort descriptor for a given tableview changes. To the best of my knowledge, there are two times when this can happen.

The first way is when you've used bindings to populate a tableview, then a column header is clicked. That's not what you're doing here.

The second way is when setSortDescriptors: is called explicitly. By default, a table has no sortDescriptor. In the code you've provided, a sortDescriptor is never set. Therefore, the sortDescriptor never changes and tableview:sortDescriptorsDidChange: will never be called.

At what point in your programs execution do you believe this method should be called?

BenCoffman
Sep 7, 2009, 07:03 PM
In Cocoa, there are often datasource or delegate methods that contain phrases like "didChange" or "willChange". These methods are called only when the value they're referring to actually changes.

The method we're looking at here, tableView:sortDescriptorsDidChange: is a method of this type. The name of the method implies that it will be called after the sort descriptor for a given tableview changes. To the best of my knowledge, there are two times when this can happen.

The first way is when you've used bindings to populate a tableview, then a column header is clicked. That's not what you're doing here.

The second way is when setSortDescriptors: is called explicitly. By default, a table has no sortDescriptor. In the code you've provided, a sortDescriptor is never set. Therefore, the sortDescriptor never changes and tableview:sortDescriptorsDidChange: will never be called.

At what point in your programs execution do you believe this method should be called?

Warwick -- another good post -- I'll stop saying this because it's getting redundant.

I would like it to be called when I hit the table's column header.

I think you are telling me i have not set any criteria for my table column to be sorted, but with setSortDescriptors I can set criteria which in turn will cause my sortDescriptor tableview to get called

I can't seem to find any good example on how to use setSortDescriptors? Links or suggestions?

kainjow
Sep 8, 2009, 12:06 PM
tableView:sortDescriptorsDidChange: is a 10.6 only method. Are you certain you're building against the 10.6 libraries?

The docs are semi-misleading. The @protocol methods are 10.6+ but they still work on 10.3 and up if you target that SDK. I'm guessing the reason they say 10.6+ is because if you link to the 10.6 SDK they'll use conformsToProtocol, but for 10.3+ it might use respondsToSelector:


Regarding getting this method to work, the way I've always done it is to setup the sort descriptors for each column in IB. Then that method gets called magically and you just resort your array, although I believe an array controller will handle it all if you're using that.