How to sort contacts in iOS 7.1
Asked Answered
D

2

6

After the last update to Xcode 5.1, the Apple's example code for sorting Address Book stopped working. URL: https://developer.apple.com/library/ios/documentation/ContactData/Conceptual/AddressBookProgrammingGuideforiPhone/Chapters/DirectInteraction.html

Example Code

ABAddressBookRef addressBook = ABAddressBookCreate();
CFArrayRef people = ABAddressBookCopyArrayOfAllPeople(addressBook);
CFMutableArrayRef peopleMutable = CFArrayCreateMutableCopy(
                                          kCFAllocatorDefault,
                                          CFArrayGetCount(people),
                                          people
                                  );


CFArraySortValues(
        peopleMutable,
        CFRangeMake(0, CFArrayGetCount(peopleMutable)),
        (CFComparatorFunction) ABPersonComparePeopleByName,
        (void*) ABPersonGetSortOrdering()
);

CFRelease(addressBook);
CFRelease(people);
CFRelease(peopleMutable);

But now, this code raises a warning

Cast to 'void *' from smaller integer type 'ABPersonSortOrdering' (aka 'unsigned int')

In this line

(void*) ABPersonGetSortOrdering())

How should I modified this code?

I actually looked into Apples' forums, Googled it, Stackoverflowed it, and no joy yet.

Hope you can help me.

UPDATE

It seams using 64bit has something to do with this warning. It coincide with the inclusion of the my new iPhone 5s.

Decorticate answered 17/3, 2014 at 20:34 Comment(2)
I duplicated your code and I didn't get the warning you mention, however I should point out that your creation method is deprecated and instead of ABAddressBookCreate you should be using ABAddressBookCreateWithOptions(). You should also be checking you have permission to access the address book beforehand with ABAddressBookRequestAccessWithCompletion too. See here for more details... #12084143Intraatomic
Thanks for mentioning the deprecation, however the code that I pasted here was extracted from Apple's documentation. In my code I'm using ABAddressBookCreateWithOptions for creating the address book.Decorticate
L
20

As you stated, the problem is with the new 64 bit architecture. (void*) is a 32 bit pointer for a 32 bit architecture, but a 64 bit pointer for a 64 bit architecture. The function ABPersonGetSortOrdering() returns a value of type ABPersonCompositeNameFormat which is specified as a uint32_t in ABPerson.h. So the warning is letting you know that a 64 bit pointer is pointing to a 32 bit number.

The warning can be eliminated by typecasting the return value to an unsigned long. This is perfect because it will be 64 bits on a 64 bit architecture and 32 bits on a 32 bit architecture.

(void *)(unsigned long)ABPersonGetSortOrdering()

Hope this helps!

Lieutenancy answered 19/3, 2014 at 21:46 Comment(1)
How about (void *)(NSUInteger)ABPersonGetSortOrdering(). I think it will work each 32bit And 64bit compile environments.Wearable
I
0

I suspect your problem is to do with the differences between 64bit and 32bit architecture, Xcode 5.1 has enabled 64bit support by default. If pointers are 64 bits and ints are 32 bits, an int is too small to hold a pointer value.

You can disable 64bit compilation for your App by going to your target > build settings but I would highly recommend you don't do that. Besides, The following code works for me, it also implements the new creation method, and correctly implements the authorisation check (this makes sure the user has granted permission for your App to access the contacts)

CFErrorRef * err;

ABAddressBookRef addressBook = ABAddressBookCreateWithOptions(NULL, err);

ABAddressBookRequestAccessWithCompletion(addressBook, ^(bool granted, CFErrorRef error) {

    if (!granted) {
        // No Access to address book, user has denied
        return;
    }

    CFArrayRef people = ABAddressBookCopyArrayOfAllPeople(addressBook);
    CFMutableArrayRef peopleMutable = CFArrayCreateMutableCopy(kCFAllocatorDefault,
                                                               CFArrayGetCount(people),
                                                               people);


    CFArraySortValues(peopleMutable,
                      CFRangeMake(0, CFArrayGetCount(peopleMutable)),
                      (CFComparatorFunction) ABPersonComparePeopleByName,
                      (void*) ABPersonGetSortOrdering());

    CFRelease(addressBook);
    CFRelease(people);
    CFRelease(peopleMutable);

});

Although if I wanted to be really picky, i'd say you should probably cast the people array into an NSArray like this:

NSArray *people = (__bridge_transfer NSArray*)ABAddressBookCopyArrayOfAllPeople(addressBook);

Then consider implementing your sorting methods using NSSortDescriptors as they are likely to be faster, and certainly a more modern way of doing things.

Intraatomic answered 17/3, 2014 at 21:26 Comment(3)
Honestly I am surprised the API has not been redone for Foundation. It's definitely time.Madalinemadalyn
Thanks for your input on 64bit. The code that you post doesn't differ from what I have, and it also have the same warning on the ABPersonComparePeopleByNameDecorticate
It certainly does differ, It uses the non deprecated constructor for ABAddressBookRef and it ensures the user has granted permission for contact access beforehand, something which would cause your current App to crash should the user deny access. Furthermore, as I said there is no warning in my version of xcode for the line you are talking about.Intraatomic

© 2022 - 2024 — McMap. All rights reserved.