ios - 如何仅获取设备上每个联系人的第一个电话号码?

标签 ios objective-c cncontact cncontactstore

我有一个表格 View ,显示设备上所有联系人的姓名。这些名称来自名为 contactsArray 的数组。对于每个 contact 对象,我获取 phoneNumbers 对象并将号码放入另一个名为 phoneNumberArray 的数组中。当我将它们放入表格 View 时,它会显示每个联系人及其相应的号码......但仅限这么长时间。当我下降几十行时,号码不再与正确的联系人匹配,因为某些 contact 对象包含一个带有多个电话号码的 phoneNumbers 对象。如何仅获取每个对象的第一个电话号码,以便我拥有相同数量的联系人和电话号码?

这是我的代码:

    @property (nonatomic, strong) NSMutableArray *contactsArray;
    @property (nonatomic, strong) NSMutableArray *phoneNumberArray;

    @end

    @implementation Contacts

    - (void)viewDidLoad
    {

        [super viewDidLoad];

        self.phoneNumberArray = [[NSMutableArray alloc]init];
        self.contactsArray = [[NSMutableArray alloc]init];
        [self fetchContactsandAuthorization];
    }

    - (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
    {
        return 1;
    }

    -(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
    {
        return  self.contactsArray.count;
    }

    -(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
    {
        static NSString *cellId = @"contactCell";
        ContactCell *cell = [tableView dequeueReusableCellWithIdentifier:cellId];

        CNContact *contact = self.contactsArray[indexPath.row];
        NSString *phone = self.phoneNumberArray[indexPath.row];

        NSString *contactName = [NSString stringWithFormat:@"%@ %@",contact.givenName,contact.familyName];
        NSString *contactNumber = phone;

        cell.name.text = contactName;
        cell.number.text = contactNumber;
        [cell.inviteBtn addTarget:self action:@selector(openMessagesForContact:) forControlEvents:UIControlEventTouchUpInside];

        return cell;
    }

    - (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
    {
        return 72;
    }

    -(void)fetchContactsandAuthorization
    {
        // Request authorization to Contacts
        CNContactStore *store = [[CNContactStore alloc] init];
        [store requestAccessForEntityType:CNEntityTypeContacts completionHandler:^(BOOL granted, NSError * _Nullable error) {
            if (granted == YES)
            {
                CNContactStore *addressBook = [[CNContactStore alloc]init];

                NSArray *keysToFetch =@[CNContactFamilyNameKey,
                                        CNContactGivenNameKey,
                                        CNContactPhoneNumbersKey];

                CNContactFetchRequest *fetchRequest = [[CNContactFetchRequest alloc]initWithKeysToFetch:keysToFetch];

                [addressBook enumerateContactsWithFetchRequest:fetchRequest error:nil usingBlock:^(CNContact * _Nonnull contact, BOOL * _Nonnull stop) {

                    [self.contactsArray addObject:contact];

                    NSString *phone;

                    for (CNLabeledValue *label in contact.phoneNumbers) {
                        phone = [label.value stringValue];
                        if ([phone length] > 0) {
                            [self.phoneNumberArray addObject:phone];
                        }
                    }
                }];

                dispatch_async(dispatch_get_main_queue(), ^{
                    [self.contactsTableView reloadData];
                });

            }
        }];
    }

@end

最佳答案

您的方法的问题在于您正在创建一个全局电话号码数组,然后将所有电话号码添加到其中。相反,您只想添加第一个电话号码。

我将修改以下代码:

for (CNLabeledValue *label in contact.phoneNumbers) {
    phone = [label.value stringValue];
    if ([phone length] > 0) {
        [self.phoneNumberArray addObject:phone];
        break;
    }
}

if (contact.phoneNumbers.count == 0) {
    [self.phoneNumberArray addObject: @""];
}

逻辑现在已经改变:

  1. 我们将每个用户添加到一个数组中
  2. 在电话号码数组中,我们只添加其对应的第一个号码
  3. 现在我们的两个数组是直接链接的。最后值得检查的是,电话号码数组始终与用户数组具有相同的计数
  4. 我们调用break来退出

有了这个新功能 - 并在 3 中提到过。我们需要添加更多检查。例如,如果用户没有任何电话号码怎么办?在这种情况下,我们需要添加一个空白电话号码以确保号码适合联系人。

if ([label isEqualTo: contact.phoneNumbers.lastValue]) {
    [self.phoneNumberArray addObject: @""];
}

上面还有另一个潜在的检查 - 如果我们循环所有电话号码并且不添加号码,那么无论如何我们都会添加一个空白号码。您需要查看数据并了解可能遇到的不同场景。

替代解决方案:

上述解决方案是一种让您的代码正常工作的快速解决方案 - 尽管我个人不太喜欢这种方法 - 如果您想为每个数字使用多个数字怎么办?如果你想点击某个用户查看所有号码怎么办?在构建代码时,值得考虑如何确保以后可以更轻松地重构代码。

不会有不同的情况(Coredata 和对象等),我更愿意为每个联系人提供一组字典。该数组将存储他们的详细信息(姓名、电话号码等),并且可以在每个单元格中轻松访问。

[addressBook enumerateContactsWithFetchRequest:fetchRequest error:nil usingBlock:^(CNContact * _Nonnull contact, BOOL * _Nonnull stop) {

    NSMutableArray * phoneNumbersTemp = [NSMutableArray new];

    for (CNLabeledValue *label in contact.phoneNumbers) {
        phone = [label.value stringValue];
        if ([phone length] > 0) {
            [phoneNumbersTemp addObject:phone];
        }
    }

    NSDictionary * contactDict = @{name: contact.name,
                                   phoneNumbers: phoneNumbersTemp}

    [self.contactsArray addObject:contactDict];
}];

注意:这是 sudo 代码,尚未经过测试 - 这是为了突出显示该方法

这种代码将允许您访问每个单元格中的第一个电话号码(只需获取每个用户的联系电话词典并获取第一个条目),但也允许您构建高级功能的联系人对象。

关于ios - 如何仅获取设备上每个联系人的第一个电话号码?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/47785039/

相关文章:

ios - 如何调用特定的 TableViewCell

iphone - 如何制作通用的iOS应用程序

ios - 如何从 CNContactStore ios 获取 RecordID

Swift CN联系人

ios - 从 CNContactStore 获取所有 CNGroup

iOS:对 <UITableViewController> 开始/结束外观转换的调用不平衡

iphone - 在 MySQL 中的何处存储 AES_ENCRYPT 的 key ?

ios - 带有 spritebuilder 的无标签,无法弄清楚如何修复它

objective-c - 从 AVAssetWriter 读取实时 H.264 输出时数据损坏

ios - 在最后一张图像处停止 UIimageview 动画