epo*_*gee 38 cocoa-touch objective-c duplicates abaddressbook abrecord
我即将推出的应用的一些测试用户报告说,联系人列表包含大量重复记录.我正在使用结果ABAddressBookCopyArrayOfAllPeople作为我自定义的联系人表视图的数据源,这让我感到困惑,结果与iPhone的"联系人"应用程序不同.
当仔细查看"联系人"应用程序时,重复项似乎来自具有"链接卡"的条目.下面的屏幕截图有点混淆,但正如你在我最右边的应用程序中看到的那样,"Celine"显示两次,而在左边的Contacts应用程序中只有一个"Celine".如果您单击该单个联系人的行,您将获得一张带有两个"链接卡"的"统一信息"卡(如中心所示,我没有使用Celine的联系方式,因为它们不适用于一个屏幕截图):

围绕"联卡"的问题,有相当一几个主题上苹果的论坛上为最终用户,但除了一个事实,即许多点到404支持页面,我不能真实地去周围固定了我所有的应用程序的用户的地址簿.我更愿意优雅地处理它而不会打扰用户.更糟糕的是,似乎我不是唯一一个有这个问题的人,因为WhatsApp显示的是包含重复联系人的相同列表.
为了清楚重复联系人的起源,我不是存储,缓存或以其他方式试图聪明地了解数组ABAddressBookCopyArrayOfAllPeople返回.因此,重复记录直接来自API调用.
有谁知道如何处理或检测这些链接卡,防止重复记录显示?Apple的联系人应用程序可以做到,我们其他人也可以这样做吗?
更新:我写了一个库并把它放在Cocoapods上以解决手头的问题.请参阅下面的答案
Dan*_*tay 35
一种方法是仅从默认地址簿源中检索联系人:
ABAddressBookRef addressBook = ABAddressBookCreate();
NSArray *people = (__bridge NSArray *)ABAddressBookCopyArrayOfAllPeopleInSource(addressBook, ABAddressBookCopyDefaultSource(addressBook));
Run Code Online (Sandbox Code Playgroud)
但那太蹩脚了吧?它针对的是设备上的通讯簿,但不是可能位于Exchange或其他花哨的同步通讯簿中的额外联系人.
所以这是您正在寻找的解决方案:
ABPersonCopyArrayOfAllLinkedPeople)您现在有一个NSSet包含链接的ABRecord对象的NSSets.总体NSSet将与"联系人"应用程序中的联系人数量相同.
示例代码:
NSMutableSet *unifiedRecordsSet = [NSMutableSet set];
ABAddressBookRef addressBook = ABAddressBookCreate();
CFArrayRef records = ABAddressBookCopyArrayOfAllPeople(addressBook);
for (CFIndex i = 0; i < CFArrayGetCount(records); i++)
{
NSMutableSet *contactSet = [NSMutableSet set];
ABRecordRef record = CFArrayGetValueAtIndex(records, i);
[contactSet addObject:(__bridge id)record];
NSArray *linkedRecordsArray = (__bridge NSArray *)ABPersonCopyArrayOfAllLinkedPeople(record);
[contactSet addObjectsFromArray:linkedRecordsArray];
// Your own custom "unified record" class (or just an NSSet!)
DAUnifiedRecord *unifiedRecord = [[DAUnifiedRecord alloc] initWithRecords:contactSet];
[unifiedRecordsSet addObject:unifiedRecord];
CFRelease(record);
}
CFRelease(records);
CFRelease(addressBook);
_unifiedRecords = [unifiedRecordsSet allObjects];
Run Code Online (Sandbox Code Playgroud)
我已经在我的应用程序中使用ABPersonCopyArrayOfAllLinkedPeople()一段时间了.不幸的是,我刚刚发现它并不总是做正确的事情.例如,如果您有两个具有相同名称但一个设置了"isPerson"标志且另一个没有设置的联系人,则上述功能将不会将它们视为"链接".为什么这是一个问题?因为Gmail(交换)源不支持此布尔标志.如果您尝试将其保存为false,则会失败,并且您保存在其中的联系人将在下次运行您的应用时返回,与您在iCload(CardDAV)中保存的联系人取消链接.
与社交服务类似的情况:Gmail不支持它们,如果有一个facebook帐户而另一个没有,则上面的功能会看到两个名称相同的联系人.
我正在切换到我自己的name-and-source-recordID-only算法,用于确定是否应将两个联系人记录显示为单个联系人.更多的工作,但有一线希望:ABPersonCopyArrayOfAllLinkedPeople()是对接慢.
@Daniel Amitay提供的方法包含很有价值的掘金,但不幸的是代码还没有准备好使用.对联系人进行良好的搜索对我和许多应用程序至关重要,因此我花了很多时间来做到这一点,同时也解决了iOS 5和6兼容地址簿访问问题(通过块处理用户访问) ).它解决了许多链接卡由于错误同步的源和新添加的Facebook集成卡.
我编写的库使用内存(可选磁盘)Core Data存储来缓存地址簿记录ID,提供简单的后台线程搜索算法,返回统一的地址簿卡.
源代码可以在我的github存储库中找到,它是一个CocoaPods pod:
pod 'EEEUnifiedAddressBook'
Run Code Online (Sandbox Code Playgroud)
使用新的iOS 9 Contacts Framework,您终于可以拥有统一的联系人.
我向您展示两个例子:
1)使用快速枚举
//Initializing the contact store:
CNContactStore* contactStore = [CNContactStore new];
if (!contactStore) {
NSLog(@"Contact store is nil. Maybe you don't have the permission?");
return;
}
//Which contact keys (properties) do you want? I want them all!
NSArray* contactKeys = @[
CNContactNamePrefixKey, CNContactGivenNameKey, CNContactMiddleNameKey, CNContactFamilyNameKey, CNContactPreviousFamilyNameKey, CNContactNameSuffixKey, CNContactNicknameKey, CNContactPhoneticGivenNameKey, CNContactPhoneticMiddleNameKey, CNContactPhoneticFamilyNameKey, CNContactOrganizationNameKey, CNContactDepartmentNameKey, CNContactJobTitleKey, CNContactBirthdayKey, CNContactNonGregorianBirthdayKey, CNContactNoteKey, CNContactImageDataKey, CNContactThumbnailImageDataKey, CNContactImageDataAvailableKey, CNContactTypeKey, CNContactPhoneNumbersKey, CNContactEmailAddressesKey, CNContactPostalAddressesKey, CNContactDatesKey, CNContactUrlAddressesKey, CNContactRelationsKey, CNContactSocialProfilesKey, CNContactInstantMessageAddressesKey
];
CNContactFetchRequest* fetchRequest = [[CNContactFetchRequest alloc] initWithKeysToFetch:contactKeys];
[fetchRequest setUnifyResults:YES]; //It seems that YES is the default value
NSError* error = nil;
__block NSInteger counter = 0;
Run Code Online (Sandbox Code Playgroud)
在这里,我使用快速枚举循环遍历所有统一联系人:
BOOL success = [contactStore enumerateContactsWithFetchRequest:fetchRequest
error:&error
usingBlock:^(CNContact* __nonnull contact, BOOL* __nonnull stop) {
NSLog(@"Unified contact: %@", contact);
counter++;
}];
if (success) {
NSLog(@"Successfully fetched %ld contacts", counter);
}
else {
NSLog(@"Error while fetching contacts: %@", error);
}
Run Code Online (Sandbox Code Playgroud)
2)使用unifiedContactsMatchingPredicateAPI:
// Contacts store initialized ...
NSArray * unifiedContacts = [contactStore unifiedContactsMatchingPredicate:nil keysToFetch:contactKeys error:&error]; // Replace the predicate with your filter.
Run Code Online (Sandbox Code Playgroud)
PS你可能也对这个新的API感兴趣CNContact.h:
/*! Returns YES if the receiver was fetched as a unified contact and includes the contact having contactIdentifier in its unification */
- (BOOL)isUnifiedWithContactWithIdentifier:(NSString*)contactIdentifier;
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
13779 次 |
| 最近记录: |