PDA

View Full Version : Core Data Fetch With Sorting




BadWolf13
Nov 2, 2010, 07:03 PM
Ok, doing my first Core Data app, and I'm running into one issue. Core Data apparently doesn't always save and fetch in the same order, so every time I start the app, the objects are being displayed in my tableView in a different order. Now I understand the idea of using sort descriptors with a fetch request, but the Array Controller that I'm binding to the tableView and Managed Object Context is apparently fetching automatically, cause there's no code in my program that's doing that. So how do I make it sort, when I'm not controlling the fetch process with code?



JoshDC
Nov 3, 2010, 10:42 AM
NSArrayController has setSortDescriptors: and setAutomaticallyRearrangesObjects: (or manually rearrangeObjects). Using these appropriately on the ArrayController you're binding to should do what you want and completely remove the need to sort at fetch time.

BadWolf13
Nov 3, 2010, 05:33 PM
Thank you, but wouldn't binding the array controller to a sort descriptor interfere with the user's ability to sort the table by clicking on the column headings?

JoshDC
Nov 3, 2010, 06:27 PM
I don't have a great example to test it out with, but it works fine when reversing sort order in a single column table. I would try it out and see.

BadWolf13
Nov 3, 2010, 07:49 PM
This is a multiple column tableView though. The user should be able to sort using any of the columns.

BadWolf13
Nov 4, 2010, 11:36 AM
Ok, it works, but it's highlighting the column of the tableView that it's sorting by. It doesn't look very professional and could be rather distracting to the user. I also don't see why it's doing that, given that the array controller is doing the sorting, not the tableView.

JoshDC
Nov 4, 2010, 04:02 PM
Untick the column checkbox in the selection section of the table view's attribute inspector, or call setAllowsColumnSelection:NO.

If you're using complex sort descriptors, like manufacturer then part number, you might want to add something like this to your table view's datasource:


- (void)tableView:(NSTableView *)aTableView
sortDescriptorsDidChange:(NSArray *)oldDescriptors
{
NSSortDescriptor *newSortdescriptor = [[aTableView sortDescriptors] objectAtIndex:0];

if ([[newSortdescriptor key] isEqualTo:@"manufacturer"] ) {
NSSortDescriptor *partDescriptor = [NSSortDescriptor sortDescriptorWithKey:@"partNumber"
ascending:YES
selector:@selector(caseInsensitiveCompare:)];


NSSortDescriptor *manDescriptor = [NSSortDescriptor sortDescriptorWithKey:@"manufacturer"
ascending:[newSortdescriptor ascending]
selector:@selector(caseInsensitiveCompare:)];



NSArray *sortDescriptors = [NSArray arrayWithObjects:manDescriptor,partDescriptor, nil];

[arrayController setSortDescriptors:sortDescriptors];
}
}

BadWolf13
Nov 5, 2010, 12:54 AM
The column checkbox is already unchecked.

Let me try to explain this better. With the highlight of the column heading, it looks like the sorting is happening in the tableView, but I want it to happen in the array controller or, ideally, within the managed object model. Shouldn't that be a lot simpler?

jared_kipe
Nov 15, 2010, 09:04 AM
NSArrayController has a couple of fine looking methonds.

- setSortDescriptors:
- setAutomaticallyRearrangesObjects:

JoshDC
Nov 15, 2010, 12:49 PM
So you want to be able to select the sort column, but not have that column header become highlighted? While I don't understand your reasoning for this as it changes expected behaviour, I've been able to do this, albeit hackily, by using setHighlightedTableColumn:.

This method seems to only work if it's sent a valid NSTableColumn (so you can't just send nil and have no column header highlighted) so what I've done is create an extra table column, set it to hidden and then set that as highlighted when sort descriptors change (see previous post on the data source method for this).

BadWolf13
Nov 15, 2010, 05:00 PM
Jared, thank you. Those are exactly the methods I'm using through an IBOutlet linked to my Array Controller. It is sorting properly, but it's having an undesirable side effect.

You know when you click on the a column header to sort by that column, it highlights the column header in blue and gives you a triangle showing the direction of the sort? Well, it's doing that when the window first opens, for the column corresponding to my NSSortDescriptor. Many programs that I use sort the information in their tableView, but don't highlight the column headers until the user selects one to sort manually. That's the effect that I'm looking for. Does it make sense?

jared_kipe
Nov 16, 2010, 01:11 PM
Jared, thank you. Those are exactly the methods I'm using through an IBOutlet linked to my Array Controller. It is sorting properly, but it's having an undesirable side effect.

You know when you click on the a column header to sort by that column, it highlights the column header in blue and gives you a triangle showing the direction of the sort? Well, it's doing that when the window first opens, for the column corresponding to my NSSortDescriptor. Many programs that I use sort the information in their tableView, but don't highlight the column headers until the user selects one to sort manually. That's the effect that I'm looking for. Does it make sense?

The effect you are looking for makes complete sense. Some information on how your program is wired up is required.

Are you subclassing NSArrayController?
Why use IBOutlets to these methods? Why not call them programmatically when either your NSArrayController is created, or inside your subclasses init methods?

EDIT: Oh and if you post code, I can probably get this working no problem.

BadWolf13
Nov 16, 2010, 05:23 PM
1. I'm not subclassing NSArrayController.
2. The use of IBOutlet is how I know of connecting my code to my XIB file, which is where the NSArrayController is.
3. Not much code to post in relation to this particular issue, since most of it's being handled by bindings.

Speaking of bindings, I tried getting rid of these two lines of code and using the Sort Descriptor binding in the XIB file, but that's not doing anything.

BadWolf13
Nov 16, 2010, 05:51 PM
Ok, another question. If I unchecked the Prepares Content box for my array controller in Interface Builder, could I then still get the information into it by writing code similar to;


[arrayController setContent [moc executeFetchRequest:request error:&error]];


with moc and request being defined earlier? If so, where in my code would I put that? ApplicationDidFinishLaunching, Init?

jared_kipe
Nov 16, 2010, 10:15 PM
I personally believe the simplest thing to try would be to subclass NSArrayController and override only initWithCoder to call super's initWithCoder and then setup

- setSortDescriptors:
- setAutomaticallyRearrangesObjects:

As needed.

In InterfaceBuilder just change the class of your already wired up one to be your subclass and all set.

Probably take 5 minutes total.

BadWolf13
Nov 17, 2010, 11:41 AM
Ok, couple of questions. First, why would I use initWithCoder instead of just init? Also, I'm currently calling those two methods in my applicationDidFinishLaunching method. Is it really going to make that much of a difference to move them into an init method?

JoshDC
Nov 17, 2010, 12:49 PM
initWithCoder: is what gets called in place of init when initialising an object that's be serialised in a .nib. It won't (or at least shouldn't) make a difference if you move the method calls there.

I understand your problem but can't think of a neat solution. For what it's worth I prefer to have the sorted column always highlighted and would find what your describing confusing. Sorry I can't help further.

jared_kipe
Nov 17, 2010, 07:54 PM
Ok, couple of questions. First, why would I use initWithCoder instead of just init? Also, I'm currently calling those two methods in my applicationDidFinishLaunching method. Is it really going to make that much of a difference to move them into an init method?

Hold on, so if you DO call those methods it sorts and also highlights.

If you don't then it doesn't sort but also doesn't highlight?

BadWolf13
Nov 17, 2010, 08:58 PM
Hold on, so if you DO call those methods it sorts and also highlights.

If you don't then it doesn't sort but also doesn't highlight?

Exactly.

jared_kipe
Nov 17, 2010, 11:47 PM
You are correct then.

You'll want to use a fetch request that has sort descriptors assigned for it. Then assign that array into your NSArrayController. You could take some bindings out and put it into a subclass of NSArrayController's initWithCoder:
Or try to put it in your application delegate.

BadWolf13
Nov 18, 2010, 11:36 AM
Thank you. Now here's the million dollar question. The array controller is part of my mainmenu.xib file, so where in my app delegate do I put my fetch request? Init, applicationDidFinishLaunching, or WindowDidLoad?

jared_kipe
Nov 18, 2010, 11:41 AM
Probably either of the last two. Just try it out.

BadWolf13
Nov 18, 2010, 05:28 PM
Thanks dude, I put some code into ApplicationDidFinishLaunching, and called the setContent for my NSArrayController IBOutlet, and it works beautifully. No highlight until the user clicks on a heading. Then, when I reopen the app, it's back to the default sorting. Thank you for all your help.

jared_kipe
Nov 19, 2010, 12:05 PM
Glad it all worked out.