2012-07-05 92 views
38

my upcoming app的一些beta用戶報告說,聯繫人列表包含大量重複記錄。我使用ABAddressBookCopyArrayOfAllPeople的結果作爲我自定義的聯繫人表格視圖的數據源,它讓我很困惑,結果與iPhone的「聯繫人」應用程序不同。處理由於iOS中的鏈接卡的重複聯繫人地址簿API

當仔細查看聯繫人應用程序時,似乎重複來自具有「鏈接卡片」的條目。下面的屏幕截圖已經被混淆了一下,但正如你在我的應用中看到的那樣,「Celine」出現了兩次,而左側的Contacts應用中只有一個「Celine」。如果您點擊該單一聯繫人的行,您將得到一張帶有兩個「鏈接卡」的「統一信息」卡(如中心所示,我沒有使用塞琳的聯繫詳細信息,因爲它們不適用於一個屏幕截圖)

Screenshot

圍繞「聯卡」的問題,有一個quitefew topicsApple's forums最終用戶,但除了一個事實,即許多指向一個404 support page,我不能真實地去周圍所有固定的我的應用用戶的地址簿。我很想優雅地處理它,而不會打擾用戶。更糟糕的是,似乎我不是唯一一個遇到這個問題的人,因爲WhatsApp is showing the same list containing duplicate contacts

只是爲了清楚重複聯繫人的來歷,我不存儲,緩存或以其他方式試圖對數組ABAddressBookCopyArrayOfAllPeople返回智能。所以重複記錄直接來自API調用。

有誰知道如何處理或檢測這些連接的卡,防止重複的記錄顯示出來? Apple的通訊錄應用程序可以實現,我們其他人也可以這樣做嗎?

更新:我寫了一個庫,並把它放在Cocoapods上來解決手頭的問題。見下面

+1

我認爲這是一個更大的問題在iOS6,與Facebook的聯繫人。但是,因爲我回到了iOS5我無法驗證它是否是相同的。 – Jankeesvw 2012-07-07 11:13:42

+0

Facebook可能也會添加鏈接的卡...然後有人必須考慮正確的方式來顯示列表,如果它不是ABAddressBookCopyArrayOfAllPeople – epologee 2012-07-11 07:24:40

回答

5

的做法是@Daniel Amitay其中提供了很有價值的掘金,可惜代碼還沒有準備好使用。對聯繫人進行良好的搜索對於我的和許多應用程序至關重要,因此我花了相當多的時間來解決這個問題,同時還解決了iOS 5和6兼容的地址簿訪問問題(處理用戶通過塊訪問)。它解決了由於源代碼不正確以及新添加的Facebook集成中的卡片導致的衆多鏈接卡片。

我編寫的庫使用內存(可選磁盤)核心數據存儲來緩存地址簿記錄標識,提供簡單的後臺線程搜索算法,可返回統一的地址簿卡。

的源代碼可以在github repository of mine,這是一個CocoaPods莢:

pod 'EEEUnifiedAddressBook' 
+0

404上的存儲庫,你有沒有移動它? – andreacipriani 2014-08-17 09:58:10

+0

啊,是的,它後來轉移到一個單獨的存儲庫。恐怕需要一點更新。 – epologee 2014-08-18 14:04:43

33

一種方法我的回答是隻檢索默認的地址簿源聯繫人:

ABAddressBookRef addressBook = ABAddressBookCreate(); 
NSArray *people = (__bridge NSArray *)ABAddressBookCopyArrayOfAllPeopleInSource(addressBook, ABAddressBookCopyDefaultSource(addressBook)); 

但是,這是瘸腿的,對不對?它針對的是設備上的通訊簿,但不包括可能在Exchange或其他奇特同步通訊簿中的額外聯繫人。

因此,這裏是你要尋找的解決方案:

  1. 迭代通過ABRecord引用
  2. 抓住每一個相應的 「鏈接引用」(使用ABPersonCopyArrayOfAllLinkedPeople
  3. 他們捆綁在一個NSSet中(以便分組可以唯一標識)
  4. 將該NSSet添加到另一個NSSet
  5. 獲利?

您現在有一個NSSet,其中包含NSSets鏈接的ABRecord對象。總體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]; 
+0

這是蹩腳的Apple不會爲我們提供此功能,但您的統一通訊錄可以完美解決問題!我會留下這個問題,以防接近蘋果的任何人想要稱重,但我認爲+100即將發佈。謝謝! – epologee 2012-07-14 11:16:36

+0

Daniel,我想知道爲什麼你從GitHub中移除了DAUnifiedAddressBook存儲庫。聽起來很有用。 – 2012-09-12 16:55:28

+0

= /這是一個我沒有完全開發的止損措施。實際上,它只是執行了上述步驟的「generateUnifiedContacts」調用。我有計劃進一步開發它,但最終它不會比自己完成上述任務更好,然後根據需要處理參考。 – 2012-09-12 18:16:59

8

在我的應用程序有一段時間我一直在使用ABPersonCopyArrayOfAllLinkedPeople()現在。不幸的是,我剛剛發現它並不總是做正確的事情。例如,如果您有兩個具有相同名稱的聯繫人,但其中一個設置了「isPerson」標誌,另一個沒有設置,則上述功能不會將其視爲「已鏈接」。爲什麼這是一個問題?由於Gmail(交換)源不支持此布爾標誌。如果您嘗試將其保存爲false,則會失敗,並且保存在其中的聯繫人將在下次運行時返回,因爲它與您在iCload(CardDAV)中保存的聯繫人沒有鏈接。

與社交服務類似的情況:Gmail不支持它們,上面的函數會看到兩個名稱相同但名稱不同的聯繫人,如果其中一個擁有Facebook帳戶而另一個沒有。

我正在切換到我自己的名稱和源記錄ID唯一算法,以確定是否應將兩個聯繫人記錄顯示爲單個聯繫人。更多的工作,但有一線希望:ABPersonCopyArrayOfAllLinkedPeople()是屁股緩慢。

+1

歡迎來到Stack Overflow。之前有兩個答案,其中一個已經投票贊成很多,另一個來自原始海報,標識他們實際解決問題的方式。我不確定你提出的建議與他爲其他人在Github下載中使用的建議有什麼不同,但我不確定你的答案是否真的有幫助,因爲不清楚其他人可以得到你的建議解決方案代碼我不會爲此投下你的票,但請確保考慮你提供的答案是否提供了新的信息,如果是這樣的老問題。 – 2012-10-07 04:35:32

+3

我認爲克里斯托弗的答案主要是爲了提供一些關於ABPersonCopyArrayOfAllLinkedPeople()實現中可能存在缺陷的背景信息。我沒有在其他地方看到這些信息,所以我認爲這對我或其他人可能有用。 – 2012-10-25 17:47:39

+0

我認爲這是一個非常翔實的答案,其中包含的信息難以獲得與問題相關的信息以及之前給出的答案。 Upvoted。 – Tim 2015-03-04 02:17:00

0

我得到的所有來源ABAddressBookCopyArrayOfAllSources,移動默認的ABAddressBookCopyDefaultSource到第一位置,然後遍歷它們,並讓所有的人源ABAddressBookCopyArrayOfAllPeopleInSource跳過那些我見過之前鏈接,然後讓人們掛在每ABPersonCopyArrayOfAllLinkedPeople

4

隨着新的iOS 9 聯繫人框架你終於可以有你的統一聯繫人。

我告訴你兩個例子:

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; 

我在這裏循環使用快速列舉:

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

2)使用unifiedContactsMatchingPredicate API :

// Contacts store initialized ... 
NSArray * unifiedContacts = [contactStore unifiedContactsMatchingPredicate:nil keysToFetch:contactKeys error:&error]; // Replace the predicate with your filter. 

P.S您可能也有興趣在這個新的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; 
相關問題