Question

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.

Was it helpful?

Solution

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!

OTHER TIPS

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.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top