iosnssortdescriptor

Using NSSortDescriptor With Multiple Keys and Missing Data


I would like to sort user-created contacts where the contacts have a hodgepodge of data. Some contacts may have every field or attribute filled in e.g. lastName, firstName, company, phone, email whereas others may have just a first name or just an email or just a company.

The customary way to use NSSort descriptors is to create an NSArray where the first sortDescriptors in the array take precedence with ties broken by each successive one. Thus:

NSSortDescriptor *last =[[NSSortDescriptor alloc]initWithKey:@"lastname" ascending:YES];
NSSortDescriptor *first =[[NSSortDescriptor alloc]initWithKey:@"firstname" ascending:YES]; 
NSSortDescriptor *company =[[NSSortDescriptor alloc]initWithKey:@"company" ascending:YES]; 
NSSortDescriptor *email =[[NSSortDescriptor alloc]initWithKey:@"email" ascending:YES];   
[request setSortDescriptors:[NSArray arrayWithObjects:last, first, company,email, nil]];

applied to

  Allen,Joe,microsoft,ja@microsoft.com|Allen,Zack,google,nil|Smith,Tom,Apple,nil 

would give you:

Allen, Joe
Allen, Zack
Smith, Tom

which looks fine.

However, if your data looks like:

Allen,Joe,nil,ja@gmail.com|nil,Zack,nil,zack@msn.com|nil,nil,nil,raj@gmailcom|nil,nil,cloudflare,nil

The above would give you:

cloudflare
raj@gmail.com
Zack
Allen, Joe

which is a mess.

In the second case, I would like something that makes more sense perhaps if only email sorted by email followed by if only company sorted by company followed by lastname, followed by first name

raj@gmail.com
cloudflare
Allen, Joe
Zack

or, even, whatever fields they have ranked in order

Allen, Joe
cloudflare
raj@gmail.com
Zack

Is there any way to accomplish this? How does apple do it with their contacts?

Thanks for any suggestions


Solution

  • Instead of initialising your sort descriptors using

    initWithKey:ascending:
    

    you could use

    initWithKey:ascending:comparator:
    

    In the comparator block

    ^NSComparisonResult(id obj1, id obj2)  {…}
    

    you could explicitly check for nil objects, and set the comparison result as appropriate.
    I did not check this, but it should work.