Чтение адреса электронной почты из контактов не удается из-за странной проблемы с памятью - PullRequest
5 голосов
/ 10 апреля 2010

Я в тупике.

Я пытаюсь получить список всех адресов электронной почты, которые есть у человека. Я использую ABPeoplePickerNavigationController, чтобы выбрать человека, который, кажется, все в порядке. Я устанавливаю свой

ABRecordRef personDealingWith;

от аргумента person до

- (BOOL)peoplePickerNavigationController:(ABPeoplePickerNavigationController *)peoplePicker shouldContinueAfterSelectingPerson:(ABRecordRef)person property:(ABPropertyID)property identifier:(ABMultiValueIdentifier)identifier {

и до этого момента все кажется нормальным. Первый раз, когда выполняется следующий код, все хорошо. При последующем запуске я могу получить проблемы. Сначала код:

// following line seems to make the difference (issue 1)
// NSLog(@"%d", ABMultiValueGetCount(ABRecordCopyValue(personDealingWith, kABPersonEmailProperty)));

// construct array of emails
ABMultiValueRef multi = ABRecordCopyValue(personDealingWith, kABPersonEmailProperty);
CFIndex emailCount = ABMultiValueGetCount(multi);

if (emailCount > 0) {
    // collect all emails in array
    for (CFIndex i = 0; i < emailCount; i++) {
        CFStringRef emailRef = ABMultiValueCopyValueAtIndex(multi, i);
        [emailArray addObject:(NSString *)emailRef];
        CFRelease(emailRef);
    }
}

// following line also matters (issue 2)
CFRelease(multi);

Если скомпилировано как написано, нет ошибок или проблем статического анализа. Это вылетает с

*** -[Not A Type retain]: message sent to deallocated instance 0x4e9dc60

ошибка.

Но подождите, это еще не все! Я могу исправить это одним из двух способов.

Во-первых, я могу раскомментировать NSLog в верхней части функции. Я получаю утечку из ABRecordCopyValue NSLog каждый раз, но код, кажется, работает нормально.

Также я могу закомментировать

CFRelease(multi);

в конце, который делает то же самое. Статические ошибки компиляции, но работает код.

Так что без утечки эта функция вылетает. Чтобы предотвратить сбой, мне нужно кровоизлияние в память. Ни то, ни другое не является хорошим решением.

Кто-нибудь может указать, что происходит?

Ответы [ 2 ]

13 голосов
/ 27 июня 2011

Оказалось, что я не правильно хранил ABRecordRef personDealingWith переменную. Я все еще не уверен, как это сделать правильно, но вместо того, чтобы использовать функциональность в другой подпрограмме (выполненной позже), я сейчас выполняю грубую работу в методе делегата и использую полученные результаты на досуге. Новая (рабочая) рутина:

- (BOOL)peoplePickerNavigationController:(ABPeoplePickerNavigationController *)peoplePicker shouldContinueAfterSelectingPerson:(ABRecordRef)person {
    // as soon as they select someone, return
    personDealingWithFullName = (NSString *)ABRecordCopyCompositeName(person);
    personDealingWithFirstName = (NSString *)ABRecordCopyValue(person, kABPersonFirstNameProperty);
    // construct array of emails
    [personDealingWithEmails removeAllObjects];
    ABMutableMultiValueRef multi = ABRecordCopyValue(person, kABPersonEmailProperty);
    if (ABMultiValueGetCount(multi) > 0) {
        // collect all emails in array
        for (CFIndex i = 0; i < ABMultiValueGetCount(multi); i++) {
            CFStringRef emailRef = ABMultiValueCopyValueAtIndex(multi, i);
            [personDealingWithEmails addObject:(NSString *)emailRef];
            CFRelease(emailRef);
        }
    }
    CFRelease(multi);
    return NO;
}
0 голосов
/ 16 июня 2014

Я столкнулся с подобной проблемой. Проблема может заключаться в том, как вы установите

ABRecordRef personDealingWith;

Кажется, что вы не можете просто сделать:

ABRecordRef personDealingWith = person;

Потому что personDealingWith остается нулевым. Вместо этого я сделал следующее:

ABRecordID personID = ABRecordGetRecordID(person);
ABAddressBookRef addressBook = ABAddressBookCreateWithOptions(NULL, NULL);
personDealingWith = ABAddressBookGetPersonWithRecordID(addressBook, personID);
...