Список контактов устройства

Задача: взять контакты пользователя из устройства и вывести их в виде таблицы. Оказалось, это довольно просто, достаточно вставить одну встроенную в Foundation библиотеку и написать один метод.

Сначала импортируем библиотеку:

import UIKit
import Contacts

После чего создаём модель для контакта. Имя, фамилия и номер телефона - этого достаточно:

struct FetchedContact {
    let givenName: String
    let familyName: String
    let phoneNumber: String
}

В ViewController создаём массив:

private var contacts: [FetchedContact] = []

Добавим метод fetchContacts(для запроса контактов. Сначала он просит доступ к контактам, после чего, если доступ дан (if granted {) он делает запрос к списку контактов (я оставил ключевые слова для имён, фамилий и телефонов, хотя последний не использовал), затем добавляет их в массив, и там же этот массив сортирует по алфавиту. После этого в главном треде происходит обновление таблицы (всё это время таблица пустая, и наверное, при большом списке контактов, заполнение массива и его сортировка могут занять некоторое время, в этом случае стоит добавить индикатор активности).

func fetchContacts() {
    let store = CNContactStore()
    store.requestAccess(for: .contacts) { (granted, error) in
        if let error = error {
            print(“Failed to request access:”, error)
            return
        }
        guard granted else {
            print(“Access denied”)
            return
        }
        let keys = [CNContactGivenNameKey, CNContactFamilyNameKey, CNContactPhoneNumbersKey]
        let request = CNContactFetchRequest(keysToFetch: keys as [CNKeyDescriptor])
        do {
            try store.enumerateContacts(with: request, usingBlock: { (contact, _) in
                self.contacts.append(FetchedContact(givenName: contact.givenName,
                                                    familyName: contact.familyName,
                                                    phoneNumber: contact.phoneNumbers.first?.value.stringValue ?? “”))
                self.contacts.sort { $0.givenName < $1.givenName }
            })
        } catch let error {
            print(“Failed to enumerate contact:”, error)
        }
        DispatchQueue.main.async {
            self.tableView.reloadData()
        }
    }
}

Не забываем его вызвать:

override func viewDidLoad() {
    super.viewDidLoad()
    fetchContacts()
}

Вызов функции - чуть ли не самое важное при её написании

Для работы таблицы добавляем расширение с функциями таблицы:

extension ViewController: UITableViewDelegate, UITableViewDataSource {

    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return contacts.count
    }

    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let cell = UITableViewCell()
        cell.textLabel?.text = contacts[indexPath.row].givenName
        return cell
    }

    func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
        tableView.deselectRow(at: indexPath, animated: true)
        print(contacts[indexPath.row])
    }

}

При нажатии на ячейку в консоль выводится имя-фамилия-номер контакта.

Ещё одна вещь, которую нужно сделать: в файле Info.plist добавляем строчку

Key Type Value
Privacy - Contacts Usage Description String Please grant access to your contacts to invite friends

Готово!

June 10, 2020