how can I Add a ABRecordRef to a NSMutableArray in

2019-02-09 03:07发布

问题:

I want to create an array of ABRecordRef(s) to store contacts which have a valid birthday field.

   NSMutableArray* bContacts = [[NSMutableArray alloc] init];
   ABAddressBookRef addressBook = ABAddressBookCreate();
   CFArrayRef allPeople = ABAddressBookCopyArrayOfAllPeople(addressBook);
   CFIndex nPeople = ABAddressBookGetPersonCount(addressBook);

   for( int i = 0 ; i < nPeople ; i++ )
   {
       ABRecordRef ref = CFArrayGetValueAtIndex(allPeople, i );
       NSDate* birthdayDate = (NSDate*) ABRecordCopyValue(ref, kABPersonBirthdayProperty);
       if (birthdayDate != nil){
           [bContacts addObject:ref];
       }
   }

The compiler shows this warning: warning: passing argument 1 of 'addObject:' discards qualifiers from pointer target type I searched the web and found I have to cast ABRecordRef to a ABRecord* to be able to store in a NSMutableArray.

[bContacts addObject:(ABRecord*) ref];

But it seems ABRecord is not part of iOS frameworks. Now how I store ABRecordRef to NSMutableArray?

回答1:

[bContacts addObject:(id) ref];


回答2:

A ABRecordRef is a typedef for CFTypeRef and that in turn resolves to const void *. And this is where the warning comes from: with the call to addObject:, the const qualifier is "lost".

In this case we know it's OK. A CFTypeRef is a semi-highlevel type, instances of this type support CFRetain and CFRelease. That in turn means it's probably OK to cast it to id and treat it as a NSObject. So you should be simply able to do:

[bContacts addObject:(id)ref];


回答3:

Create an NSObject wich store your ABRecordRef like this :

// ABContact.h
@interface ABContact : NSObject
{
    ABRecordRef _record;
}

@property (nonatomic, readonly) NSDate *birthday;

- (id)initWithRecord:(ABRecordRef)aRecord;

@end

// ABContact.m
@implementation ABContact

#pragma mark - Init

- (id)initWithRecord:(ABRecordRef)aRecord;
{
    if ((self = [super init]))
        _record = CFRetain(aRecord);
    return self;
}


#pragma mark - Getter

- (NSDate *)birthday
{
    return (NSDate *)ABRecordCopyValue(record, kABPersonBirthdayProperty) autorelease];
}


#pragma mark - Memory management

- (void)dealloc
{
    CFRelease(_record);
    [super dealloc];
}

@end


You should take a look at the Erica Sadum library the author of the iPhone cookbook. Here is the code wich inspire this code -> url



回答4:

I know this is an old question, but since the introduction of ARC, this is handled in a different way.

There are two possible ways of adding an ABRecordRef to an NSMutableArray now, both of which require a bridged cast:

Direct conversion

[bContacts addObject:(__bridge id)(ref)];

This simply converts the ABRecordRef pointer, and should be used, if you didn't create ref yourself using a method that has Create in its name.

Transfer ownership to ARC

[bContacts addObject:CFBridgingRelease(ref)];

This converts the ABRecordRef pointer, and in addition transfers its ownership to ARC. This should be used, if you used e.g. ABPersonCreate() to create a new person.

More information can be found in the Transitioning to ARC Release Notes. There are also many other informative sources here on Stack Overflow, such as this question.