2017-10-25 16 views
5

Tôi không biết liệu câu hỏi này có đủ điều kiện để ở đây hay không, nhưng thậm chí sau rất nhiều nghiên cứu, tôi không thể tìm thấy hướng dẫn phù hợp cho câu hỏi này. Tôi hy vọng tôi nhận được câu trả lời ở đây.Ứng dụng nhắn tin iOS như Viber, Telegram, WhatsApp tìm nạp danh bạ nhanh như thế nào và hiệu quả

Tôi thấy rằng tất cả các ứng dụng nhắn tin như Viber, WhatsApp, Telegram tìm nạp địa chỉ liên hệ của người dùng và phân tích cú pháp nhanh và hiệu quả đến mức gần như bằng không. Tôi đã cố gắng để tái tạo điều đó nhưng chưa bao giờ thành công. Nó luôn luôn mất 40-60 giây thời gian tốt để phân tích 3000 địa chỉ liên lạc bằng cách chạy toàn bộ hoạt động trên các chủ đề nền. Thậm chí điều đó làm cho giao diện người dùng bị đóng băng trên các thiết bị chậm hơn như 5 và 5S. Sau khi tìm nạp địa chỉ liên lạc, tôi phải gửi chúng đến phần phụ trợ để xác định người dùng nào được đăng ký trên nền tảng mà cũng thêm vào tổng thời gian. Các ứng dụng được đề cập ở trên thực hiện điều này trong thời gian không!

Tôi rất vui nếu ai đó có thể đề xuất cách phân tích cú pháp các liên hệ theo cách hiệu quả nhất và nhanh hơn mà không chặn chủ đề chính.

Đây là mã, tôi sử dụng tại thời điểm này.

final class CNContactsService: ContactsService { 

private let phoneNumberKit = PhoneNumberKit() 
private var allContacts:[Contact] = [] 

private let contactsStore: CNContactStore 


init(network:Network) { 
    contactsStore = CNContactStore() 
    self.network = network 
} 

func fetchContacts() { 
    fetchLocalContacts { (error) in 
     if let uError = error { 

     } else { 
      let contactsArray = self.allContacts 
      self.checkContacts(contacts: contactsArray, checkCompletion: { (Users) in 
       let nonUsers = contactsArray.filter { contact in 
        return !Users.contains(contact) 
       } 
       self.Users.value = Users 
       self.nonUsers.value = nonUsers 
      }) 
     } 
    } 

} 

func fetchLocalContacts(_ completion: @escaping (NSError?) -> Void) { 
    switch CNContactStore.authorizationStatus(for: CNEntityType.contacts) { 
    case CNAuthorizationStatus.denied, CNAuthorizationStatus.restricted: 
     //User has denied the current app to access the contacts. 
     self.displayNoAccessMsg() 
    case CNAuthorizationStatus.notDetermined: 
     //This case means the user is prompted for the first time for allowing contacts 
     contactsStore.requestAccess(for: CNEntityType.contacts, completionHandler: { (granted, error) -> Void in 
      //At this point an alert is provided to the user to provide access to contacts. This will get invoked if a user responds to the alert 
      if (!granted){ 
       DispatchQueue.main.async(execute: {() -> Void in 
        completion(error as! NSError) 
       }) 
      } else{ 
       self.fetchLocalContacts(completion) 
      } 
     }) 

    case CNAuthorizationStatus.authorized: 
     //Authorization granted by user for this app. 
     var contactsArray = [EPContact]() 
     let contactFetchRequest = CNContactFetchRequest(keysToFetch: allowedContactKeys) 
     do { 
      //    let phoneNumberKit = PhoneNumberKit() 
      try self.contactsStore.enumerateContacts(with: contactFetchRequest, usingBlock: { (contact, stop) -> Void in 
       //Ordering contacts based on alphabets in firstname 
       if let contactItem = self.contactFrom(contact: contact) { 
       contactsArray.append(contactItem) 
       } 
      }) 
      self.allContacts = contactsArray 
      completion(nil) 
     } catch let error as NSError { 
      print(error.localizedDescription) 
      completion(error) 
     } 
    } 
} 

private var allowedContactKeys: [CNKeyDescriptor]{ 
    //We have to provide only the keys which we have to access. We should avoid unnecessary keys when fetching the contact. Reducing the keys means faster the access. 
    return [ 
     CNContactGivenNameKey as CNKeyDescriptor, 
     CNContactFamilyNameKey as CNKeyDescriptor, 
     CNContactOrganizationNameKey as CNKeyDescriptor, 
     CNContactThumbnailImageDataKey as CNKeyDescriptor, 
     CNContactPhoneNumbersKey as CNKeyDescriptor, 
    ] 
} 

private func checkUsers(contacts:[Contact],checkCompletion:@escaping ([Contact])->Void) { 
    let phoneNumbers = contacts.flatMap{$0.phoneNumbers} 
    if phoneNumbers.isEmpty { 
     checkCompletion([]) 
     return 
    } 
    network.request(.registeredContacts(numbers: phoneNumbersList), completion: { (result) in 
     switch result { 
     case .success(let response): 
      do { 
       let profiles = try response.map([Profile].self) 
       let contacts = profiles.map{ CNContactsService.contactFrom(profile: $0) } 
       checkCompletion(contacts) 
      } catch { 
       checkCompletion([]) 
      } 
     case .failure: 
      checkCompletion([]) 
     } 
    }) 
} 

static func contactFrom(profile:Profile) -> Contact { 
    let firstName = "" 
    let lastName = "" 
    let company = "" 
    var displayName = "" 
    if let fullName = profile.fullName { 
     displayName = fullName 
    } else { 
     displayName = profile.nickName ?? "" 
    } 
    let numbers = [profile.phone!] 
    if displayName.isEmpty { 
     displayName = profile.phone! 
    } 
    let contactId = String(profile.id) 

    return Contact(firstName: firstName, 
        lastName: lastName, 
        company: company, 
        displayName: displayName, 
        thumbnailProfileImage: nil, 
        contactId: contactId, 
        phoneNumbers: numbers, 
        profile: profile) 
} 

private func parsePhoneNumber(_ number: String) -> String? { 
    do { 
     let phoneNumber = try phoneNumberKit.parse(number) 
     return phoneNumberKit.format(phoneNumber, toType: .e164) 
    } catch { 
     return nil 
    } 
} 


}` 

Và các điểm tiếp xúc được lấy ở đây khi ứng dụng được khởi động

private func ApplicationLaunched() { 
    DispatchQueue.global(qos: .background).async { 
     let contactsService:ContactsService = self.serviceHolder.get() 
     contactsService.fetchContacts() 
    } 
+0

Chỉ là một câu hỏi, bạn đã thử chơi với 'allowContactKeys' chưa? Có lẽ 'CNContactThumbnailImageDataKey' quá nặng đối với 3000 địa chỉ liên lạc? Tôi không bao giờ thử nó cho nhiều địa chỉ liên lạc, nhưng tôi lấy 200 địa chỉ liên lạc gần như ngay lập tức trong ứng dụng của tôi, nhưng tôi không yêu cầu hình ảnh thu nhỏ. – TawaNicolas

+0

Bạn đã thử tìm nạp chúng theo lô chưa? – swift2geek

+0

Không chắc chắn nhưng tôi nghĩ WhatsApp đang bắt đầu đồng bộ hóa danh bạ ngay khi mở ứng dụng lần đầu tiên. Đọc https://www.quora.com/How-does-the-contacts-sync-work-in-WhatsApp/answer/Jinesh-Soni?srid=RhqE –

Trả lời

1

Tôi đoán là các số liên lạc mà bạn đang gửi đến phụ trợ là rất lớn. 3000 Địa chỉ liên hệ quá nhiều và tôi cho rằng một trong những điều sau đây đang xảy ra:

  1. Yêu cầu quá lớn và phải mất thời gian để cung cấp cho chương trình phụ trợ.
  2. Quá nặng đối với chương trình phụ trợ và phải mất thời gian để xử lý và trả lại cho khách hàng, và đây là những gì gây ra sự chậm trễ cho bạn.

Vấn đề ít có khả năng là:

  1. phương pháp phân tích cú pháp của bạn là rất nặng trên CPU. Nhưng điều này là rất khó xảy ra.

Bạn có đo thời lượng giữa quá trình phân tích cú pháp bắt đầu và kết thúc không?

Tôi nghĩ bạn nên đo khoảng thời gian giữa tất cả các hành động mà bạn đang làm, ví dụ:

  1. Đo phải mất bao lâu để lấy danh bạ từ thiết bị.
  2. Đo khoảng thời gian để phân tích cú pháp danh bạ.
  3. Đo thời gian cần để nhận phản hồi từ chương trình phụ trợ.

Điều này sẽ giúp bạn xác định chính xác những gì mất quá nhiều thời gian.

Tôi hy vọng điều này sẽ giúp giải quyết vấn đề của bạn.

+0

Cảm ơn @TawaNicolas. Giải pháp của bạn thực sự đã giúp tôi tìm ra vấn đề. Đó là 3, mà bạn đã đề cập đó là gây ra vấn đề. Chúng tôi đang sử dụng phoneNumberKit để phân tích cú pháp số và thêm mã quốc gia, siêu chậm và mất thời gian. Tôi đã chuyển sang libPhoneNumber-iOS đang hoạt động hoàn hảo. Để tìm nạp và phân tích 2900 số liên lạc, thời gian đã giảm xuống còn 3 giây từ 65 giây, bao gồm cả cuộc gọi mạng –

+0

Ngoài ra, việc đóng băng giao diện người dùng gây ra do lọc mảng. Khi chúng tôi nhận được phản hồi từ máy chủ, tôi lưu trữ tất cả các số điện thoại trong một mảng và so sánh nó với mảng của tất cả các địa chỉ liên hệ và tạo một mảng mới với tất cả các địa chỉ liên hệ không có trên nền tảng của chúng tôi. Kể từ khi nó đang xảy ra trên thread chính giao diện người dùng bị chặn chuyển sang chủ đề tiện ích toàn cầu đã ngăn chặn các UI blockage.Also, tìm nạp địa chỉ liên lạc đã được chuyển sang thread tiện ích để làm cho nó lấy nhanh hơn. –

Các vấn đề liên quan