ABRecordCopyValue () EXC_BAD_ACCESS Fout

In mijn app moet ik bepaalde eigenschappen van de gebruikerscontacten ophalen. Ik moet bijvoorbeeld de voornaam, achternaam, middelste naam, bijnaam, organisatie, functietitel, afdeling, verjaardag, e-mail, etc. van een contact ophalen. Ik heb een aantal methoden om deze eigenschappen op te halen, en slechts een paar werk, ook al ze lijken allemaal erg op elkaar. Hier is mijn code voor één methode die werkt (voornaam) en één die niet (functie) is:

+(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 is a class method defined like this:

+(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;
}

Deze methoden worden gedefinieerd in een modelklasse genaamd "PSPropertyFetcher". In mijn root view-controller plaats ik een aantal NSLog-instructies in viewDidLoad om te zien of de methoden voor het ophalen van eigenschappen correct werken. Hier is mijn code voor de tests:

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]);        
}

Dit werkt slechts gedeeltelijk; dit is de output:

2012-06-27 10: 37: 30.094 Guess Who! [80103: f803] Test voor het ophalen van eigendommen

     

2012-06-27 10: 37: 30.108 Guess Who! [80103: f803] Voornaam: Jod

     

2012-06-27 10: 37: 30.114 Guess Who! [80103: f803] Middle Name: Bob

     

2012-06-27 10: 37: 30.118 Guess Who! [80103: f803] Achternaam: Satson

     

2012-06-27 10: 37: 30.122 Guess Who! [80103: f803] Organisatie: Johnson en Johnson

     

2012-06-27 10: 37: 30.125 Guess Who! [80103: f803] Afdeling: NULL

     

2012-06-27 10: 37: 30.128 Guess Who! [80103: f803] Functietitel: NULL


2012-06-27 10: 37: 30.136 Guess Who! [80103: f803] Voornaam: Shemairan

     

2012-06-27 10: 37: 30.166 Guess Who! [80103: f803] Middle Name: Daitran

     

2012-06-27 10: 37: 30.179 Guess Who! [80103: f803] Achternaam: Catairan

     

2012-06-27 10: 37: 30.184 Guess Who! [80103: f803] Organisatie: Shmairo and Co.

     

2012-06-27 10: 37: 30.188 Guess Who! [80103: f803] Afdeling: NULL

     

2012-06-27 10: 37: 30.193 Guess Who! [80103: f803] Functietitel: NULL


2012-06-27 10: 37: 30.202 Guess Who! [80103: f803] Voornaam: Alex

     

2012-06-27 10: 37: 30.207 Guess Who! [80103: f803] Middle Name: John

     

2012-06-27 10: 37: 30.213 Guess Who! [80103: f803] Achternaam: Mais

     

2012-06-27 10: 37: 30.219 Guess Who! [80103: f803] Organisatie: Apple

     

2012-06-27 10: 37: 30.225 Guess Who! [80103: f803] Afdeling: NULL

     

2012-06-27 10: 37: 30.230 Guess Who! [80103: f803] Functietitel: NULL

In de app iOS Simulator Contacts heb ik ervoor gezorgd dat ik elk veld voor elk contact heb ingevuld, maar om een ​​of andere reden worden de velden "Afdeling" en "Taaktitel" niet correct afgedrukt.

Kortom, ik vraag me af wat er mis is met mijn "Functietitel" en "Afdeling" verzamelmethoden.

Bij voorbaat dank!

3
@JakeKing Ik update de vraag om arrayOfContacts weer te geven
toegevoegd de auteur pasawaya, de bron
Kunnen we de implementatie van [self arrayOfContacts] zien? Als het slechts een eigenschap is, waar wordt dit dan ingevuld?
toegevoegd de auteur Alexis King, de bron

4 antwoord

Hoewel het bij een kleine steekproef van een adresboek niet waarschijnlijk lijkt, heb je hier wel een geheugenlek waardoor dingen kunnen worden uitgeblazen.

Ervan uitgaande dat u arrayOfContacts gebruikt om [self contactsCount] te bepalen, lekt u telkens twee AddressBook-items door elke lus in die klassemethoden.

In dit kleine voorbeeld heb je slechts 48 adresboeken gelekt op het moment dat je contactpersonen startWithJobTitleProperty. Maar als je dit hebt getrokken uit een groter exemplaar waarbij je herhaaldelijk probeert om deze waarden te bepalen op een veel groter Adresboek, kun je honderden bengelende AddressBook-objecten rondhangen.

Voeg CFRelease toe zoals in het volgende fragment en kijk of het helpt.

+(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;
}

(fwiw, een ander ding dat je programma zal laten crashen is dat je NSUInteger gebruikt als het type loopteller, maar je test tegen een waarde die mogelijk -1 zou kunnen zijn ... en omdat 0 de grond is voor NSUInteger, als jouw adres book heeft geen contacten erin, dit zal mislukken, maar dat is niet de reden waarom deze crash plaatsvindt.)

6
toegevoegd
Ik zal het proberen en contact met je opnemen.
toegevoegd de auteur pasawaya, de bron
Nu crasht het niet en de organisatiemethode retourneert de juiste waarde, maar sommige van de andere methoden voor andere eigenschappen retourneren niet de juiste waarden.
toegevoegd de auteur pasawaya, de bron
Sorry. De functie Job Title retourneert het aantal contactpersonen dat is ingevuld met de eigenschap Functienaam. De organisatiemethode is hetzelfde maar controleert de organisatie-eigenschap. Ik heb een __ bridge_transfer voor elke methode zoals deze (en ik heb een methode voor elke eigenschap, 31 in totaal). In welke situatie klopt een __ bridge_transfer niet?
toegevoegd de auteur pasawaya, de bron
OK. Ik zal mijn methode controleren. Bedankt.
toegevoegd de auteur pasawaya, de bron
welke "organisatie" -methode? (ik veronderstel dat ik kan aannemen dat u bedoelt dat u een andere klassemethode hebt zoals die hierboven die het aantal contacten oproept met eigenschap kABPersonOrganizationProperty.) Welke andere methoden retourneren geen correcte waarden? niet alle typen retourneren hetzelfde type als u ze ophaalt, dus u moet ervoor zorgen dat uw __bridge of _bridge_transfer in elk geval klopt.
toegevoegd de auteur john.k.doe, de bron
sorry, ik was niet duidelijk. Ik bedoel het type gebruikt in de __bridge of __bridge_transfer. ik denk dat je de __bridge/__ bridge_transfer correct gebruikt in elk van deze gevallen, maar het type dat terugkomt uit het adresboek is misschien niet altijd een type dat wordt overgezet naar NSString, en als je de __bridge/__ bridge_transfer doet van iets dat geen snaar naar NSString, ik zou denken dat je problemen zou kunnen oplopen.
toegevoegd de auteur john.k.doe, de bron

Het lijkt erop dat je misschien een NULL-waarde gebruikt. Heb je geprobeerd om te testen of het NULL is voordat je de overbruggingsoverdracht uitvoert?

2
toegevoegd
Ik test niet of het een NULL-waarde is (wat ik zou moeten bedanken), maar ik heb ervoor gezorgd dat voor elk veld in de simulator een waarde werd toegevoegd voor elk contact.
toegevoegd de auteur pasawaya, de bron
Laat maar. Ik controleer eigenlijk op nulwaarden.
toegevoegd de auteur pasawaya, de bron

Dit zal je probleem misschien niet oplossen, maar ik zou een paar aanpassingen willen doen als ik jou was:

+(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;
}

Ook, @ john.k.doe vermeld, zorg ervoor dat u CFRelease (addressBook); gebruikt in uw arrayOfContacts -methode.

1
toegevoegd
Bedankt! Ik heb mijn code zodanig gewijzigd dat ik nu een adresboek zoals deze maak NSArray * contacts = [PSAddressBook arrayOfContacts] vóór de for-lus. Ik heb ook de regel CFRelease (addressBook) toegevoegd aan arrayOfContacts .
toegevoegd de auteur pasawaya, de bron

Ik ben net hetzelfde probleem tegengekomen. Zie antwoord hier van Jokinryou Tsui.

Kortom, als er een situatie is waarin u verschillende contactbronnen beschikbaar heeft en deze zijn niet allemaal lokaal (de standaardinstelling), zou het kunnen dat er een niet-overeenkomende telling is van het aantal contacten dat u trekt en probeert u toegang te krijgen tot een ABRecordRef op een index die niet bestaat. De ABRecordRef heeft een waarde (dus een NULL-controle alleen zal het niet doen), maar die waarde is rotzooi en je krijgt de SLECHTE TOEGANG wanneer je probeert om een ​​van zijn waarden te kopiëren.

Ik hoop dat dit helpt.

0
toegevoegd