简体   繁体   English

ABRecordRef字段似乎没有被填充?

[英]ABRecordRef fields don't seem to be populated?

[background: iOS 7, Xcode 5, both up to date as of Feb 2014. Test data is address book entries with multiple phone numbers and multiple addresses in addition to basic contact info, on an iPhone 5 (real device, not simulator)] [背景:iOS 7,Xcode 5,两个版本均截至2014年2月。测试数据是iPhone 5(真实设备,而非模拟器)上的通讯录条目,除了基本的联系信息外,还具有多个电话号码和多个地址。

My goal is to use the AddressBookUI methods to allow a user to specify a contact, then use the various fields (addresses, phone numbers, etc) to populate a GUI in my code. 我的目标是使用AddressBookUI方法允许用户指定联系人,然后使用各种字段(地址,电话号码等)在我的代码中填充GUI。 The ABPeoplePickerNavigationController is the standard mechanism to allow the user to pick a contact by name. ABPeoplePickerNavigationController是允许用户按名称选择联系人的标准机制。 Doing so results in this delegate method being called: 这样做导致调用此委托方法:

- (BOOL)peoplePickerNavigationController:(ABPeoplePickerNavigationController *)peoplePicker 
shouldContinueAfterSelectingPerson:(ABRecordRef)person

However if I examine the person record at this point, none of the multi-value fields have any data. 但是,如果我此时检查人员记录,则多值字段都没有任何数据。 So I extracted the RecordID , retrieved that, and the resulting ABRecordRef also has no multi-value fields filled in. 因此,我提取了RecordID并进行了检索,结果ABRecordRef也没有填写多值字段。

If I return YES from the delegate method, another UI is shown to the user with contact details displayed. 如果我从委托方法返回YES ,则会向用户显示另一个UI,并显示联系人详细信息。 Touching any field results in this delegate method call 触摸任何字段都会导致此委托方法调用

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

and that ABRecordRef has all the multi value fields filled in. 并且ABRecordRef了所有的多值字段。

I can't find any information about the records being lazily loaded, or there being either a required delay, or permissions issue that would prevent the fields from being filled in. And the code I am using to examine the records is a method, so the exact same code which finds the values in the second instance fails to find it in the first. 我找不到有关延迟加载的记录的任何信息,或者找不到所需的延迟或权限问题,这会阻止字段的填写。而我用来检查记录的代码是一种方法,因此在第二个实例中找到值的完全相同的代码无法在第一个实例中找到它。

Any suggestions about what may be going on, or how I can retrieve the full records without displaying the second UI to the user? 关于可能发生的事情或如何在不向用户显示第二个UI的情况下检索完整记录的任何建议?

I am using Apple's QuickContacts sample code. 我正在使用Apple的QuickContacts示例代码。 Here are the additions and changes I have made. 这是我所做的补充和更改。

+(NSMutableDictionary *)convertABRecordRef:(ABRecordRef)person
{
    // Initialize a mutable dictionary and give it initial values.
    NSMutableDictionary *contactInfoDict = [[NSMutableDictionary alloc] initWithCapacity:12];

    // Use a general Core Foundation object.
    CFTypeRef generalCFObject = ABRecordCopyValue(person, kABPersonFirstNameProperty);

    ABRecordID foundId = ABRecordGetRecordID(person);
    NSNumber *personIDNum = [NSNumber numberWithInteger:foundId];
    [contactInfoDict setObject:personIDNum forKey:@"recordID"];


    // Get the first name.
    if (generalCFObject)
    {
        [contactInfoDict setObject:(__bridge NSString *)generalCFObject forKey:@"firstName"];
        CFRelease(generalCFObject);
    }

    // Get the last name.
    generalCFObject = ABRecordCopyValue(person, kABPersonLastNameProperty);
    if (generalCFObject) {
        [contactInfoDict setObject:(__bridge NSString *)generalCFObject forKey:@"lastName"];
        CFRelease(generalCFObject);
    }

    generalCFObject = ABRecordCopyValue(person, kABPersonOrganizationProperty);
    if (generalCFObject) {
        [contactInfoDict setObject:(__bridge NSString *)generalCFObject forKey:@"companyName"];
        CFRelease(generalCFObject);
    }

    //ABMultiValueRef phones = ABRecordCopyValue(person, kABPersonPhoneProperty);
    //NSArray *numbers = (NSArray *)ABMultiValueCopyArrayOfAllValues(phones);


    // Get the phone numbers as a multi-value property.
    ABMultiValueRef phonesRef = ABRecordCopyValue(person, kABPersonPhoneProperty);
    CFIndex phoneCount = ABMultiValueGetCount(phonesRef);
    for (CFIndex i=0; i<ABMultiValueGetCount(phonesRef); i++) {

        CFStringRef currentPhoneLabel = ABMultiValueCopyLabelAtIndex(phonesRef, i);
        CFStringRef currentPhoneValue = ABMultiValueCopyValueAtIndex(phonesRef, i);

        if (CFStringCompare(currentPhoneLabel, kABPersonPhoneMobileLabel, 0) == kCFCompareEqualTo) {
            [contactInfoDict setObject:(__bridge NSString *)currentPhoneValue forKey:@"mobileNumber"];
        }

        if (CFStringCompare(currentPhoneLabel, kABHomeLabel, 0) == kCFCompareEqualTo) {
            [contactInfoDict setObject:(__bridge NSString *)currentPhoneValue forKey:@"homeNumber"];
        }

        if (CFStringCompare(currentPhoneLabel, kABWorkLabel, 0) == kCFCompareEqualTo) {
            [contactInfoDict setObject:(__bridge NSString *)currentPhoneValue forKey:@"workNumber"];
        }

        CFRelease(currentPhoneLabel);
        CFRelease(currentPhoneValue);
    }
    CFRelease(phonesRef);


    // Get the e-mail addresses as a multi-value property.
    ABMultiValueRef emailsRef = ABRecordCopyValue(person, kABPersonEmailProperty);
    for (int i=0; i<ABMultiValueGetCount(emailsRef); i++)
    {
        CFStringRef currentEmailLabel = ABMultiValueCopyLabelAtIndex(emailsRef, i);
        CFStringRef currentEmailValue = ABMultiValueCopyValueAtIndex(emailsRef, i);

        if (CFStringCompare(currentEmailLabel, kABHomeLabel, 0) == kCFCompareEqualTo) {
            [contactInfoDict setObject:(__bridge NSString *)currentEmailValue forKey:@"homeEmail"];
        }

        if (CFStringCompare(currentEmailLabel, kABWorkLabel, 0) == kCFCompareEqualTo) {
            [contactInfoDict setObject:(__bridge NSString *)currentEmailValue forKey:@"workEmail"];
        }

        CFRelease(currentEmailLabel);
        CFRelease(currentEmailValue);
    }
    CFRelease(emailsRef);


    // Get the first street address among all addresses of the selected contact.
    ABMultiValueRef addressRef =  ABRecordCopyValue(person, kABPersonAddressProperty);
    if (ABMultiValueGetCount(addressRef) > 0)
    {
        CFIndex numberOfAddresses = ABMultiValueGetCount(addressRef);
        for (CFIndex i=0; i<numberOfAddresses; i++)
        {
            CFStringRef label = ABMultiValueCopyLabelAtIndex(addressRef, i);
            if (label)
            {
                if (CFEqual(label, kABHomeLabel))
                {
                    NSDictionary *addressDict = (__bridge NSDictionary *)ABMultiValueCopyValueAtIndex(addressRef, 0);

                    [contactInfoDict setObject:[addressDict objectForKey:(NSString *)kABPersonAddressStreetKey] forKey:@"homeAddress"];
                    [contactInfoDict setObject:[addressDict objectForKey:(NSString *)kABPersonAddressZIPKey] forKey:@"homeZipCode"];
                    [contactInfoDict setObject:[addressDict objectForKey:(NSString *)kABPersonAddressCityKey] forKey:@"homeCity"];

                }
                else if (CFEqual(label, kABWorkLabel))
                {
                    NSDictionary *addressDict = (__bridge NSDictionary *)ABMultiValueCopyValueAtIndex(addressRef, 0);

                    [contactInfoDict setObject:[addressDict objectForKey:(NSString *)kABPersonAddressStreetKey] forKey:@"workAddress"];
                    [contactInfoDict setObject:[addressDict objectForKey:(NSString *)kABPersonAddressZIPKey] forKey:@"workZipCode"];
                    [contactInfoDict setObject:[addressDict objectForKey:(NSString *)kABPersonAddressCityKey] forKey:@"workCity"];
                }
                CFRelease(label);
            }
        }
    }
    CFRelease(addressRef);


    // If the contact has an image then get it too.
    if (ABPersonHasImageData(person)) {
        NSData *contactImageData = (__bridge NSData *)ABPersonCopyImageDataWithFormat(person, kABPersonImageFormatThumbnail);

        [contactInfoDict setObject:contactImageData forKey:@"image"];
    }


    return contactInfoDict;
}



// Displays the information of a selected person
- (BOOL)peoplePickerNavigationController:(ABPeoplePickerNavigationController *)peoplePicker shouldContinueAfterSelectingPerson:(ABRecordRef)person
{
    // only returns a few fields, and none of the multi value ones  :-(
    NSMutableDictionary *results = [QuickContactsViewController convertABRecordRef:person];

    ABAddressBookRef addressBook = ABAddressBookCreateWithOptions(NULL, NULL);
    ABRecordID foundId = ABRecordGetRecordID(person);
    ABRecordRef fullPerson = ABAddressBookGetPersonWithRecordID(addressBook, foundId);

    // also only returns a few fields!?
    NSMutableDictionary *selectedFromID = [QuickContactsViewController convertABRecordRef:fullPerson];


    return YES;
}

// Does not allow users to perform default actions such as dialing a phone number, when they select a person property.
- (BOOL)peoplePickerNavigationController:(ABPeoplePickerNavigationController *)peoplePicker shouldContinueAfterSelectingPerson:(ABRecordRef)person 
                                property:(ABPropertyID)property identifier:(ABMultiValueIdentifier)identifier
{
    // returns all simple and multi-value fields!?   
    NSMutableDictionary *results = [QuickContactsViewController convertABRecordRef:person];

    return NO;
}

EDIT: Adding my solution (thanks Thorsten!). 编辑:添加我的解决方案(感谢Thorsten!)。

- (BOOL)peoplePickerNavigationController:(ABPeoplePickerNavigationController *)peoplePicker shouldContinueAfterSelectingPerson:(ABRecordRef)person
{
    NSArray *allPersonRecords = (NSArray *)CFBridgingRelease(ABPersonCopyArrayOfAllLinkedPeople(person));
    NSLog(@"Count Linked People: %i", allPersonRecords.count);

    NSMutableDictionary *results = [[NSMutableDictionary alloc]initWithCapacity:12];
    for (int x=0; x<[allPersonRecords count]; x++)
    {
        ABRecordRef user = CFBridgingRetain([allPersonRecords objectAtIndex:x]);
        NSMutableDictionary *userFromArray = [QuickContactsViewController convertABRecordRef:user];
        [results addEntriesFromDictionary:userFromArray];  // mush them together
        CFRelease(user);
    }

    NSLog(@"finished! Total number of contact fields found:%d", [results count]);
    // do something with the data here...

    return NO;
}

One person can consist of multiple people. 一个人可以包含多个人。 Iterate through all people to get your data: 遍历所有人以获取您的数据:

NSArray *people = (NSArray *)CFBridgingRelease(ABPersonCopyArrayOfAllLinkedPeople(person));
...
ABRecordRef user = CFBridgingRetain([people objectAtIndex:i]);
...
valuesRef = ABRecordCopyValue(user, kABPersonPhoneProperty);
valuesCount = 0;
if (valuesRef != nil) valuesCount = ABMultiValueGetCount(valuesRef);
...

HTH 高温超导

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM