0

I try to load some specific contacts from address book and store ABRecordRef into a mutable array of dictionaries. I'm using ARC and here is my method:

- (ABRecordRef) findContactsMatchingFullName:(NSString *)contactFullName
{
    ABAddressBookRef ab = ABAddressBookCreateWithOptions(NULL, NULL);
    NSArray *allRecords = CFBridgingRelease(ABAddressBookCopyArrayOfAllPeople(ab));
    NSCharacterSet *space = [NSCharacterSet whitespaceCharacterSet];
    NSMutableArray *contactsMutableArray = [NSMutableArray array];
    NSDictionary *contact;

    NSUInteger numberOfContacts = allRecords.count;
    for (int i = 0; i < numberOfContacts; i++)
    {
        ABRecordRef record = (__bridge ABRecordRef)(allRecords[i]);
        NSString *fname = ( NSString *)CFBridgingRelease(ABRecordCopyValue(record, kABPersonFirstNameProperty));
        NSString *lname = ( NSString *)CFBridgingRelease(ABRecordCopyValue(record, kABPersonLastNameProperty));
        NSString *mname = ( NSString *)CFBridgingRelease(ABRecordCopyValue(record, kABPersonMiddleNameProperty));
        NSString *organization = ( NSString *)CFBridgingRelease(ABRecordCopyValue(record, kABPersonOrganizationProperty));

        if (fname || lname || mname || organization)
        {
            if (!fname) fname = @"";
            if (!lname) lname = @"";
            if (!mname) mname = @"";
            if (!organization) organization = @"";
            NSString *fullName = [[[[fname stringByAppendingFormat:@" %@", mname] stringByTrimmingCharactersInSet:space] stringByAppendingFormat:@" %@", lname] stringByTrimmingCharactersInSet:space];


            contact = [[NSDictionary alloc] initWithObjectsAndKeys:
                       (__bridge id)record, ksABRecordRef,
                       fullName, ksFullName,
                       organization, ksOrganization,
                       nil];
            [contactsMutableArray addObject:contact];
        }
    }

    if (ab) CFRelease(ab);



NSPredicate *predicate = [NSPredicate predicateWithFormat:@"%K LIKE[CD] %@ OR %K LIKE[CD] %@",
                          ksFullName, contactFullName, ksOrganization, contactFullName];


NSArray *filteredArray = [contactsMutableArray filteredArrayUsingPredicate:predicate];

if (filteredArray.count == 1)
    return (__bridge ABRecordRef)([filteredArray[0] objectForKey:ksABRecordRef]);
else
    return nil;
}

- (void)loadContacts:(NSArray*)contactNames
{
    if (!_contacts)
        _contacts = [[NSMutableArray alloc] init];
    else
        [_contacts removeAllObjects];

    for (NSString* name in contactNames)
    {        
        ABRecordRef contactRecord = [self findContactsMatchingFullName:name]; contacts

        if (contactRecord)
            [_contacts addObject:(__bridge id)contactRecord];
    }
}

in loadContacts method, after each call to findContactsMatchingFullName memory usage will go up a huge amount. Most memory usage happens after this line:

NSArray *allRecords = CFBridgingRelease(ABAddressBookCopyArrayOfAllPeople(ab));

Shouldn't CFBrigingRelease release retain count of ABAddressBookCopyArrayOfAllPeople?

Hadi Sharghi
  • 903
  • 16
  • 33
  • Yes it should. - Have you tried the Xcode "Analyze" option? – Martin R Apr 27 '14 at 15:15
  • Are you sure that it is memory leak? May be it is memory allocation that would be released later by ARC logic. – Vlad Papko Apr 27 '14 at 15:31
  • @Visput It is memory allocation but it won't be released any time and with every call of loadContacts method allocation goes up a huge amount – Hadi Sharghi Apr 28 '14 at 07:58
  • @MartinR Yes, No messages at all from Xcode Analyze. – Hadi Sharghi Apr 28 '14 at 08:03
  • Try to set @autoreleasepool on findContactsMatchingFullName method call, and check if any changes become. – Vlad Papko Apr 28 '14 at 08:25
  • @Visput autoreleasepool is not available while using ARC. – Hadi Sharghi Apr 28 '14 at 09:15
  • I think when I store some of `ABRecordRef`s from allRecords array into another variable and add that variable to a mutable array, allRecords array can not be released while that mutable array is in memory? Is it? – Hadi Sharghi Apr 28 '14 at 09:20
  • 1
    Write `@autoreleasepool {}` in source editor. You will be surprised. – Vlad Papko Apr 28 '14 at 09:20
  • @Visput I used autoreleasepool {} and nothing is changed! – Hadi Sharghi Apr 28 '14 at 09:24
  • Did you write in this way: `@autoreleasepool { ABRecordRef contactRecord = [self findContactsMatchingFullName:name]; if (contactRecord) [_contacts addObject:(__bridge id)contactRecord];}` – Vlad Papko Apr 28 '14 at 09:29
  • @Visput No, I put all codes in findContactsMatchingFullName method inside (at)autoreleasepool { // all codes // } – Hadi Sharghi Apr 28 '14 at 09:46
  • The final solution that I could advice is try to use Instruments (Allocations and Leaks). In this way you will see what code results to huge memory allocation. It will help to understand how to prevent this situation. – Vlad Papko Apr 28 '14 at 09:50

0 Answers0