Core Data Fetch With Sorting

Discussion in 'Mac Programming' started by BadWolf13, Nov 2, 2010.

  1. macrumors 6502

    Joined:
    Dec 17, 2009
    #1
    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?
     
  2. macrumors regular

    Joined:
    Apr 8, 2009
    #2
    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.
     
  3. thread starter macrumors 6502

    Joined:
    Dec 17, 2009
    #3
    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?
     
  4. macrumors regular

    Joined:
    Apr 8, 2009
    #4
    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.
     
  5. thread starter macrumors 6502

    Joined:
    Dec 17, 2009
    #5
    This is a multiple column tableView though. The user should be able to sort using any of the columns.
     
  6. BadWolf13, Nov 4, 2010
    Last edited: Nov 4, 2010

    thread starter macrumors 6502

    Joined:
    Dec 17, 2009
    #6
    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.
     
  7. macrumors regular

    Joined:
    Apr 8, 2009
    #7
    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:

    Code:
    - (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];
        }
    }
    
     
  8. thread starter macrumors 6502

    Joined:
    Dec 17, 2009
    #8
    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?
     
  9. macrumors 68030

    jared_kipe

    Joined:
    Dec 8, 2003
    Location:
    Seattle
    #9
    NSArrayController has a couple of fine looking methonds.

    - setSortDescriptors:
    - setAutomaticallyRearrangesObjects:
     
  10. macrumors regular

    Joined:
    Apr 8, 2009
    #10
    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).
     
  11. thread starter macrumors 6502

    Joined:
    Dec 17, 2009
    #11
    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?
     
  12. macrumors 68030

    jared_kipe

    Joined:
    Dec 8, 2003
    Location:
    Seattle
    #12
    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.
     
  13. thread starter macrumors 6502

    Joined:
    Dec 17, 2009
    #13
    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.
     
  14. thread starter macrumors 6502

    Joined:
    Dec 17, 2009
    #14
    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;

    Code:
    [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?
     
  15. macrumors 68030

    jared_kipe

    Joined:
    Dec 8, 2003
    Location:
    Seattle
    #15
    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.
     
  16. thread starter macrumors 6502

    Joined:
    Dec 17, 2009
    #16
    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?
     
  17. macrumors regular

    Joined:
    Apr 8, 2009
    #17
    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.
     
  18. macrumors 68030

    jared_kipe

    Joined:
    Dec 8, 2003
    Location:
    Seattle
    #18
    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?
     
  19. thread starter macrumors 6502

    Joined:
    Dec 17, 2009
    #19
    Exactly.
     
  20. macrumors 68030

    jared_kipe

    Joined:
    Dec 8, 2003
    Location:
    Seattle
    #20
    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.
     
  21. thread starter macrumors 6502

    Joined:
    Dec 17, 2009
    #21
    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?
     
  22. macrumors 68030

    jared_kipe

    Joined:
    Dec 8, 2003
    Location:
    Seattle
    #22
    Probably either of the last two. Just try it out.
     
  23. thread starter macrumors 6502

    Joined:
    Dec 17, 2009
    #23
    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.
     
  24. macrumors 68030

    jared_kipe

    Joined:
    Dec 8, 2003
    Location:
    Seattle
    #24
    Glad it all worked out.
     

Share This Page