NSSortDescriptor issue

前端 未结 4 1978
佛祖请我去吃肉
佛祖请我去吃肉 2021-01-13 20:24

I am making a contact book App where I am fetching names from AddressBook and stored them in Core data and displayed the names on a table using NSFetchedResultsControl

相关标签:
4条回答
  • 2021-01-13 21:03

    You can do this:

    sortDescriptor = [[NSSortDescriptor alloc] initWithKey:@"fullName" ascending:YES selector:@selector(localizedCaseInsensitiveCompare:)];
    

    Just make sure it doesn't affect performance in your case.

    0 讨论(0)
  • 2021-01-13 21:08

    You could store an additional attribute sortName in the entity, which is fullName if the name starts with a letter, and <C>fullName otherwise. <C> is a fixed character which is "greater" than all letters. For example

    NSString *special = @"\uE000";
    if ("fullName starts with letter")
        sortName = fullName;
    else
        sortName = [special stringByAppendingString:fullName];
    

    Now you can sort according to sortName, and the section identifier would be "#" if sortName starts with the special character.

    The disadvantage is that you have to store an additional attribute, the advantage is that you can continue to use a fetched results controller (which can use only persistent attributes for sorting).

    UPDATE: It can actually be done a bit easier.

    When you create a new entry, you set sectionIdentifier to the first character of the name if it is a letter, and to the special character otherwise:

    NSString *special = @"\uE000";
    
    if ([[NSCharacterSet letterCharacterSet] characterIsMember:[contact.contactName characterAtIndex:0]]) {
        contact.sectionIdentifier = [contact.contactName substringToIndex:1];
    } else {
        contact.sectionIdentifier = special;
    }
    

    The fetched results controller uses sectionIdentifier for grouping and sorting the sections. Entries within each section are sorted by contactName:

    NSFetchRequest *request = [NSFetchRequest fetchRequestWithEntityName:@"Contact"];
    NSSortDescriptor *sort1 = [NSSortDescriptor sortDescriptorWithKey:@"sectionIdentifier"
                 ascending:YES selector:@selector(localizedStandardCompare:)];
    NSSortDescriptor *sort2 = [NSSortDescriptor sortDescriptorWithKey:@"contactName"
                 ascending:YES selector:@selector(localizedStandardCompare:)];
    [request setSortDescriptors:@[sort1, sort2]];
    self.frc = [[NSFetchedResultsController alloc] initWithFetchRequest:request
                       managedObjectContext:self.context
                         sectionNameKeyPath:@"sectionIdentifier"
                                  cacheName:nil];
    

    All non-letter entries are now grouped in the last section. The final step is to display the correct section header # for the last section:

    - (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section {
        id <NSFetchedResultsSectionInfo> sectionInfo = [[self.frc sections] objectAtIndex:section];
        NSString *title = [sectionInfo name];
        if ([title isEqualToString:special])
            title = @"#";
        return title;
    }
    
    0 讨论(0)
  • 2021-01-13 21:11

    You could split up the results into two arrays, one that starts with alpha characters, and one that doesn't. Then just add the two together. Assuming you are starting with an array of managed objects called results:

    //Create the sort descriptor array
    NSSortDescriptor *sd = [NSSortDescriptor sortDescriptorWithKey:@"fullName" ascending:YES];
    NSArray *descriptors = [NSArray arrayWithObject:sd];
    
    //Create a sorted array of objects where fullName starts with an alpha character
    //using a Regex
    
    NSPredicate *pred = [NSPredicate predicateWithFormat:@"fullName MATCHES '^[a-zA-Z].*'"];
    
    NSArray *alpha = [[results filteredArrayUsingPredicate:pred] sortedArrayUsingDescriptors:descriptors];
    
    //Now use the alpha array to create an array of objects where the fullName does not
    //start with an alpha character
    
    NSMutableArray *nonAlpha = [results mutableCopy];
    
    [nonAlpha removeObjectsInArray:alpha];
    
    [nonAlpha sortUsingDescriptors:descriptors];
    
    //Now put them back together again
    
    NSArray *sortedResults = [alpha arrayByAddingObjectsFromArray:nonAlpha];
    
    //And if you're not using ARC!
    [nonAlpha release];
    
    0 讨论(0)
  • 2021-01-13 21:11

    You could try writing your own comparator Function

    Assuming that it is sorting ManagedObjects and they all have fullName as a field, then the following may help.

    [[NSSortDescriptor alloc] initWithKey:@"FullName" ascending:YES comparator:^NSComparisonResult(id obj1, id obj2) {
            return [[obj1 objectForKey:@"fullName"] compare:[obj2 objectForKey:@"fullName"] options:NSCaseInsensitiveSearch];
        }];
    

    The advantage of this is you can also write the NSLog for each comparison and see what is happening.

    0 讨论(0)
提交回复
热议问题