2017-10-25 78 views
5

Bu sorunun burada olup olmayacağını bilmiyorum, ama çok fazla araştırmadan sonra bile uygun bir rehber bulamadım bu soru için. Umarım burada bir cevap alırım.iOS, Viber, Telegram, WhatsApp uygulamalarını çok hızlı ve verimli bir şekilde getirmeyi nasıl başarabilir

Viber, WhatsApp, Telegram gibi tüm mesajlaşma uygulamalarının, kullanıcı temaslarını alıp, neredeyse sıfır gecikme olduğu kadar hızlı ve verimli bir şekilde ayrıştırdığını görüyorum. Bunu çoğaltmaya çalışıyordum ama asla başarılı olmadı. Arka plan iş parçacığı üzerinde tüm işlemi çalıştırarak 3000 kişi ayrıştırmak için her zaman 40-60 saniye zaman alır. Bu bile UI'nin 5 ve 5S gibi daha yavaş cihazlarda donmasına neden oluyor. Kişileri getirdikten sonra, toplam süreye ekleyen platformda hangi kullanıcının kayıtlı olduğunu belirlemek için onları arka tarafa göndermeliyim. Yukarıda belirtilen uygulamalar bunu hiçbir zaman yapmaz!

Kişiler, ana iş parçacığını engellemeden kişileri en verimli ve hızlı şekilde ayrıştırma yolu önerebilirse memnun olurum.

Şu an kullandığım kod şu an. Uygulamanın başlatıldığında

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


}` 

Ve kişiler burada alınabilmeleri

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

Sadece bir soru, 'allowedContactKeys' ile oynamayı denediniz mi? Belki de 'CNContactThumbnailImageDataKey' 3000 kişi için çok ağır mı? Bu kadar çok kişi için hiç denemedim, ancak neredeyse anında benim uygulamasında 200 kişi alıyorum, ancak küçük resimi istemiyorum. – TawaNicolas

+0

Onları toplu olarak getirmeyi denediniz mi? – swift2geek

+0

Emin değilim ama sanırım WhatsApp, kişileri açık uygulamayı ilk kez hemen senkronize etmeye başlıyor. Bu https://www.quora.com/How-does-the-contacts-sync-work-in-WhatsApp/answer/Jinesh-Soni?srid=RhqE –

cevap

1

Benim tahminim arka uca gönderiyoruz kişilerin sayısı büyük olmasıdır. 3000 Kişiler çok fazla ve bence aşağıdakilerden biri oluyor:

  1. Her iki istek de çok büyük ve arka uç için teslim zaman alıyor.
  2. Arka uç için çok ağır ve işlemek ve müşteriye geri dönmek zaman alıyor ve bu sizin için gecikmeye neden oluyor.

az muhtemel bir sorundur:

  1. Sizin ayrıştırma yöntemi CPU üzerinde çok ağır. Fakat bu pek olası değil.

Ayrıştırma başlar ve bitiyor arasındaki süreyi ölçtünüz mü?

Ben örneğin yaptığınızı tüm eylemler arasındaki süreleri ölçmek gerektiğini düşünüyorum: o cihazdan kişileri alıp ne kadar sürdüğünü

  1. ölçün.
  2. Kişileri ayrıştırmanın ne kadar sürdüğünü ölçün.
  3. Arka uçtan yanıt almak için ne kadar sürdüğünü ölçün.

Bu, tam olarak nelerin uzun sürdüğünü tam olarak belirlemenize yardımcı olur.

Umarım bu, sorununuzu çözmede yardımcı olur.

+0

Teşekkürler @TawaNicolas. Çözümünüz gerçekten sorunu anlamama yardımcı oldu. Soruna neden olduğunu belirttiğiniz 3'tür. Numaraları ayrıştırmak ve süper yavaş ve her zaman alarak ülke kodunu eklemek için phoneNumberKit kullanıyoruz. Mükemmel çalışan libPhoneNumber-iOS'a geçtim. 2900 kişi almak ve ayrıştırmak için, ağ çağrısı –

+0

da dahil olmak üzere 65 saniyeden 3 saniyeye düşürüldü. Ayrıca, UI donması, dizilerin filtrelenmesi nedeniyle ortaya çıkar. Sunucudan yanıt aldığımızda, tüm telefon numaralarını bir dizide saklıyorum ve tüm kişilerin dizisiyle karşılaştırın ve platformumuzda olmayan tüm kişilerle yeni bir dizi oluşturuyorum. Ana iş parçacığı üzerinde gerçekleştiği için, kullanıcı arabirimi, global yardımcı iş parçacığına UI engellemesini engelliyordu. Ayrıca, kişilerin getirilmesi, daha hızlı alınabilmesi için yardımcı iş parçacığına kaydırıldı. –