ABRecordCopyValue() EXC_BAD_ACCESS Ошибка

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

+(NSString *)fetchFirstnameForPersonID: (NSUInteger)identifier{

    NSString *firstName;
    ABRecordRef currentPerson = (__bridge ABRecordRef)[[PSAddressBook arrayOfContacts] objectAtIndex:identifier];

    //If the first name property exists
    if ((__bridge_transfer NSString *)ABRecordCopyValue(currentPerson, kABPersonFirstNameProperty) != NULL){
    
        firstName = (__bridge_transfer NSString *)ABRecordCopyValue(currentPerson, kABPersonFirstNameProperty);        
    }    
    //If the first name property does not exist
    else{
        firstName = @"NULL";
    }
    return firstName;    
}

+(NSString *)fetchJobTitleForPersonID: (NSUInteger)identifier{

    NSString *jobTitle;
    ABRecordRef currentPerson = (__bridge ABRecordRef)[[PSAddressBook arrayOfContacts] objectAtIndex:identifier];

    if ((__bridge_transfer NSString *)ABRecordCopyValue(currentPerson, kABPersonJobTitleProperty) != NULL){
    
        jobTitle = (__bridge_transfer NSString *)ABRecordCopyValue(currentPerson, kABPersonJobTitleProperty);        
    }    
    else{
    
        jobTitle = @"NULL";
    }
    return jobTitle;    
}

arrayOfContacts — это метод класса, определенный следующим образом:

+(NSArray *)arrayOfContacts{

    //Creates an ABAddressBookRef instance containing the data from the address book database
    ABAddressBookRef addressBook = ABAddressBookCreate();

    //Creates an NSArray from the CFArrayRef using toll-free bridging
    NSArray *arrayOfPeople = (__bridge_transfer NSArray *)ABAddressBookCopyArrayOfAllPeople(addressBook);

    CFRelease(addressBook);

    return arrayOfPeople;
}

Эти методы определены в классе модели PSPropertyFetcher. В моем корневом контроллере представления я поместил несколько операторов NSLog в viewDidLoad, чтобы проверить, правильно ли работают методы извлечения свойств. Вот мой код для тестов:

NSLog(@"Property Fetchers Test\n");

for(NSUInteger i = 0; i <= ([PSAddressBook contactsCount]-1); i++){

    NSLog(@"First Name: %@", [PSPropertyFetcher fetchFirstnameForPersonID:i]);
    NSLog(@"Middle Name: %@", [PSPropertyFetcher fetchMiddlenameForPersonID:i]);
    NSLog(@"Last Name: %@", [PSPropertyFetcher fetchLastnameForPersonID:i]);
    NSLog(@"Organization: %@", [PSPropertyFetcher fetchOrganizationForPersonID:i]);
    NSLog(@"Department: %@", [PSPropertyFetcher fetchDepartmentForPersonID:i]);        
    NSLog(@"Job Title: %@\n\n", [PSPropertyFetcher fetchJobTitleForPersonID:i]);        
}

Это работает только частично; это вывод:

2012-06-27 10:37:30.094 Угадай, кто![80103:f803] Тест сборщиков свойств

2012-06-27 10:37:30.108 Угадай, кто![80103:f803] Имя: Джод

2012-06-27 10:37:30.114 Угадай, кто![80103:f803] Отчество: Боб

2012-06-27 10:37:30.118 Угадай, кто![80103:f803] Фамилия: Сатсон

2012-06-27 10:37:30.122 Угадай, кто![80103:f803] Организация: Джонсон и Джонсон

2012-06-27 10:37:30.125 Угадай, кто![80103:f803] Отдел: NULL

2012-06-27 10:37:30.128 Угадай, кто![80103:f803] Должность: NULL


2012-06-27 10:37:30.136 Угадай, кто![80103:f803] Имя: Шемайран

2012-06-27 10:37:30.166 Угадай, кто![80103:f803] Второе имя: Дайтран

2012-06-27 10:37:30.179 Угадай, кто![80103:f803] Фамилия: Катаран

2012-06-27 10:37:30.184 Угадай, кто![80103:f803] Организация: Шмайро и Ко.

2012-06-27 10:37:30.188 Угадай, кто![80103:f803] Отдел: NULL

2012-06-27 10:37:30.193 Угадай, кто![80103:f803] Должность: NULL


2012-06-27 10:37:30.202 Угадай, кто![80103:f803] Имя: Алекс

2012-06-27 10:37:30.207 Угадай, кто![80103:f803] Второе имя: Джон

2012-06-27 10:37:30.213 Угадай, кто![80103:f803] Фамилия: Кукуруза

2012-06-27 10:37:30.219 Угадай, кто![80103:f803] Организация: Apple

2012-06-27 10:37:30.225 Угадай, кто![80103:f803] Отдел: NULL

2012-06-27 10:37:30.230 Угадай, кто![80103:f803] Должность: NULL

В приложении iOS Simulator Contacts я обязательно заполнил каждое поле для каждого контакта, но по какой-то причине поля «Отдел» и «Должность» печатаются неправильно.

По сути, мне интересно, что не так с моими методами получения названия должности и отдела.

Заранее спасибо!


person pasawaya    schedule 24.06.2012    source источник
comment
Можем ли мы увидеть реализацию [self arrayOfContacts]? Если это просто недвижимость, то где она заселена?   -  person Alexis King    schedule 26.06.2012
comment
@JakeKing Я обновляю вопрос, чтобы показать arrayOfContacts   -  person pasawaya    schedule 26.06.2012


Ответы (4)


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

Предполагая, что вы используете arrayOfContacts для определения [self contactsCount], вы будете пропускать 2 элемента AddressBook каждый раз через каждый цикл в этих методах класса.

В этом небольшом примере у вас будет только утечка 48 адресных книг к тому времени, когда вы начнете contactWithJobTitleProperty. Но если вы вытащили это из более крупного примера, где вы неоднократно пытаетесь определить эти значения в гораздо большей AddressBook, у вас могут быть сотни висящих объектов AddressBook.

Добавьте CFRelease, как показано в следующем фрагменте кода, и посмотрите, поможет ли это.

+(NSArray *)arrayOfContacts{

    //Creates an ABAddressBookRef instance containing the data from the address book database
    ABAddressBookRef addressBook = ABAddressBookCreate();

    //Creates an NSArray from the CFArrayRef using toll-free bridging
    NSArray *arrayOfPeople = (__bridge_transfer NSArray *)ABAddressBookCopyArrayOfAllPeople(addressBook);
    CFRelease(addressBook);

    return arrayOfPeople;
}

(между прочим, отдельная вещь, которая приведет к сбою вашей программы, заключается в том, что вы используете NSUInteger в качестве типа счетчика цикла, но вы проверяете значение, которое потенциально может быть -1... и поскольку 0 является полом для NSUInteger, если ваш адрес в книге нет контактов, это не удастся, но это не причина этого сбоя.)

person john.k.doe    schedule 26.06.2012
comment
Я попробую это и вернусь к вам. - person pasawaya; 27.06.2012
comment
Теперь он не падает, и метод организации возвращает правильное значение, но некоторые другие методы для других свойств не возвращают правильные значения. - person pasawaya; 27.06.2012
comment
какой метод организации? (я полагаю, я мог бы предположить, что вы имеете в виду, что у вас есть другой метод класса, подобный приведенным выше, который извлекает количество контактов со свойством kABPersonOrganizationProperty.) Какие другие методы не возвращают правильные значения? не все типы возвращают один и тот же тип, когда вы их извлекаете, поэтому вы должны убедиться, что ваши __bridge или _bridge_transfer имеют смысл в каждом случае. - person john.k.doe; 27.06.2012
comment
Прости. Метод Должность возвращает количество контактов с заполненным свойством должности. Метод организации тот же, но проверяется свойство организации. У меня есть __bridge_transfer для каждого подобного метода (и у меня есть метод для каждого свойства, всего 31). В какой ситуации __bridge_transfer не имеет смысла? - person pasawaya; 27.06.2012
comment
извините, я не ясно выразился. я имел в виду тип, используемый в __bridge или __bridge_transfer . я думаю, что вы правильно используете __bridge/__bridge_transfer в каждом из этих случаев, но тип, возвращаемый из адресной книги, не всегда может быть типом, который передается в NSString, и если вы выполняете __bridge/__bridge_transfer из чего-то, что не является string в NSString, я думаю, у вас могут возникнуть проблемы. - person john.k.doe; 27.06.2012
comment
В порядке. Я проверю свой метод. Спасибо. - person pasawaya; 27.06.2012

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

person lyptt    schedule 26.06.2012
comment
Я не проверяю, является ли это значением NULL (за что я должен поблагодарить), но я добавил значение для каждого контакта для каждого поля в симуляторе. - person pasawaya; 26.06.2012

Это может не решить вашу проблему, но на вашем месте я бы внес пару корректировок:

+(NSUInteger)contactsWithJobTitleProperty{
    NSUInteger contactNumber = 0;
    // don't call arrayOfContacts in the loop -- 
    // when you do this you are creating a new address book 
    // each time the loop executes
    NSArray *contacts = [self arrayOfContacts];
    for(NSUInteger increment = 0; increment <= (contacts.count-1); increment++){
        ABRecordRef currentPerson = (__bridge ABRecordRef)[contacts objectAtIndex:increment];
        NSString *valueTest = (__bridge_transfer NSString *)ABRecordCopyValue(currentPerson, kABPersonJobTitleProperty);

        if(valueTest != NULL) {
            contactNumber++;
        }
    }
    return contactNumber;
}

Кроме того, @john.k.doe упомянул, что обязательно используйте CFRelease(addressBook); в методе arrayOfContacts.

person Michael Frederick    schedule 27.06.2012
comment
Спасибо! Я изменил свой код, так что теперь я создаю адресную книгу, подобную этой, NSArray *contacts = [PSAddressBook arrayOfContacts] перед циклом for. Я также добавил строку CFRelease(addressBook) в arrayOfContacts. - person pasawaya; 27.06.2012

Только что столкнулся с той же проблемой. См. ответ Джокинрю Цуй здесь.

По сути, если есть ситуация, когда у вас есть разные источники контактов, и не все они локальные (по умолчанию), вы можете столкнуться с несоответствием количества контактов, которые вы извлекаете, и попытаться получить доступ к ABRecordRef по несуществующему индексу. ABRecordRef будет иметь значение (поэтому проверка NULL сама по себе этого не сделает), но это значение будет мусором, и вы получите ПЛОХОЙ ДОСТУП при попытке скопировать любое из его значений.

Надеюсь это поможет.

person Chase Holland    schedule 08.07.2015