sajwan
sajwan

Reputation: 333

Contacts loading too slow in some devices

I am using following code to load contacts from phonebook but in some iPhone devices it loads very slow. Even contacts are loading in background thread. In some devices it loads contacts quickly but in some devices its too slow.

How can i solve this issue?

//calling method to return contacts

DispatchQueue.global(qos: .background).async {
            self.contacts = self.returnContacts(searchBy: nil)
            DispatchQueue.main.async {
                self.tblView.reloadData()
            }
        } 

//method to return contacts

func returnContacts(searchBy:String?) -> NSArray {


            let status = CNContactStore.authorizationStatus(for: .contacts)


            if (status == .denied || status == .restricted) {

                DispatchQueue.main.async {
                    let alertController = UIAlertController(title: "", message: "This app previously was refused permissions to contacts. Please go to settings and grant permission to this app so it can use contacts", preferredStyle: .alert)
                    alertController.addAction(UIAlertAction(title: "OK", style: .default, handler: nil))

                    self.present(alertController, animated: true, completion: nil)
                }

                return NSArray()

            }

            let contactStore = CNContactStore()
            let keysToFetch = [
                CNContactFormatter.descriptorForRequiredKeys(for: .fullName),

                CNContactPhoneNumbersKey] as [Any]
            // Get all the containers

            var results: [CNContact] = []

            do {

                    var allContainers: [CNContainer] = []
                     allContainers = try contactStore.containers(matching: nil)

                     // Iterate all containers and append their contacts to our results array
                    for container in allContainers {
                        let fetchPredicate = CNContact.predicateForContactsInContainer(withIdentifier: container.identifier)
                        do {
                            let containerResults = try contactStore.unifiedContacts(matching: fetchPredicate, keysToFetch: keysToFetch as! [CNKeyDescriptor])

                            results.append(contentsOf: containerResults)
                        } catch {
                            //print("Error fetching results for container")
                        }
                    }
              //  }

            } catch {
               // print("Error fetching containers")
            }
        //    print(results)

            results.sort{$0.givenName < $1.givenName} // sorting array by name

    // Converting Array of CNContatcts into array of Dictionaries

            var conatctsArr = Array<Any>()

            for contactDetail in results  {
                var contactDic = Dictionary<String, String>()
                contactDic["givenName"] = contactDetail.givenName + " " +
                contactDetail.familyName
                let phoneNumbers : [CNLabeledValue<CNPhoneNumber>] = contactDetail.phoneNumbers

                for number in phoneNumbers {
                    contactDic["phoneNumber"] = number.value.stringValue
                    conatctsArr.append(contactDic)

                }
            }

            // filter array

            if searchBy != nil {
                let predicate=NSPredicate(format: "SELF.givenName CONTAINS[cd] %@", searchBy!)
                let mobileNumberpredicate = NSPredicate(format: "phoneNumber CONTAINS[cd] %@", searchBy!)
                let compoundPredicate = NSCompoundPredicate.init(type: .or, subpredicates: [predicate,mobileNumberpredicate])
                let arr = (conatctsArr as NSArray).filtered(using: compoundPredicate) as NSArray

                conatctsArr = arr as! Array<Any>
            }

            ///////////////////////////


     //Arranging array of contatcts in sections

            let finalArr = NSMutableArray()

            for contactDetail in conatctsArr {

                var contactDic = Dictionary<String, String>()
                contactDic = contactDetail as! Dictionary
                let name = contactDic["givenName"] ?? ""// Getting First character of name
                var key = String()
                if name.characters.count > 0 {
                    let index1 = name.index((name.startIndex), offsetBy: 1)
                    key = name.substring(to: index1)
                }
                else {
                    key = ""
                }
                // getting all contatcts starting with particular character
                let predicate=NSPredicate(format: "SELF.givenName beginswith[c] %@",key )
                let filteredArr = (conatctsArr as NSArray).filtered(using: predicate)

                var dic = Dictionary<String, Any>()
                dic["key"] = key
                dic["values"] = filteredArr

                if filteredArr.count > 0  && !(finalArr.contains(dic)) {
                    finalArr.add(dic)
                }
            }
            return finalArr
        }

Upvotes: 0

Views: 558

Answers (1)

brandonscript
brandonscript

Reputation: 72855

I would try a higher priority QoS level like User-initiated. From the docs:

Background: Work that operates in the background and isn’t visible to the user, such as indexing, synchronizing, and backups. Focuses on energy efficiency.

User-initiated: Work that the user has initiated and requires immediate results, such as opening a saved document or performing an action when the user clicks something in the user interface. The work is required in order to continue user interaction. Focuses on responsiveness and performance.

I suspect in your case that on the older devices, background tasks are being completed on a first-in, last-out basis, and are given a very low priority, resulting in a slow return of data.

Upvotes: 1

Related Questions