๊ธ€ ์ž‘์„ฑ์ž: ์ด์ง€์›๐ŸŒฉ๏ธ

๊ฐœ์š”

Contacts ํ”„๋ ˆ์ž„์›Œํฌ ํ†บ์•„๋ณด๊ธฐ

Contacts ํ”„๋ ˆ์ž„์›Œํฌ ๋ฌธ์„œ๋ฅผ ์ฐธ๊ณ ํ•ด์„œ ์‚ฌ์šฉ์ž์˜ ์—ฐ๋ฝ์ฒ˜๋ฅผ ๊ฐ€์ ธ์™€์„œ ํ…Œ์ด๋ธ”๋ทฐ๋ฅผ ํ†ตํ•ด ๋ณด์—ฌ์ฃผ์ž.

 

๐Ÿ”จ ์‚ฌ์šฉ์ž์˜ ์—ฐ๋ฝ์ฒ˜๋ฅผ ๊ฐ€์ ธ์™€์„œ ๋ณด์—ฌ์ฃผ๊ธฐ

UI ๊ตฌ์„ฑํ•˜๋Š” ๋ถ€๋ถ„์€ ํŒจ์Šค. ์ฝ”๋“œ๋‚˜ ์Šคํ† ๋ฆฌ๋ณด๋“œ๋กœ ํ…Œ์ด๋ธ”๋ทฐ์™€ ์…€ ๊ตฌ์„ฑ์„ ํ•ด์ฃผ๋ฉด ๋œ๋‹ค. ์…€์˜ ์Šคํƒ€์ผ์€ Subtitle๋กœ ์ง€์ •ํ•ด์คฌ๋‹ค. ๋ฐ์ดํ„ฐ๋ฅผ ๋งŽ์ด ๊ฐ€์ ธ์™€์„œ ๋ณด์—ฌ์ค„ ๊ฒŒ ์•„๋‹ˆ๋ผ์„œ ๊ฐ„๋‹จํ•˜๊ฒŒ ํ–ˆ๋‹ค.

๊ทธ๋‹ค์Œ์œผ๋กœ Fetching Contacts ๋ฌธ๋‹จ์— ์žˆ๋Š” ์ฝ”๋“œ๋ฅผ ๊ทธ๋Œ€๋กœ ๋”ฐ๋ผ ํ•˜๋ฉด ๋‹ค์Œ๊ณผ ๊ฐ™์€ ์ฝ”๋“œ๋ฅผ ์ž‘์„ฑํ•  ์ˆ˜ ์žˆ๋‹ค.

override func viewDidLoad() {
    super.viewDidLoad()

    self.fetchContacts()
}

func fetchContacts() {
    let store = CNContactStore()
    do {
        let predicate = CNContact.predicateForContacts(matchingName: "Appleseed")
                let keysToFetch = [CNContactGivenNameKey, CNContactFamilyNameKey] as [CNKeyDescriptor]
        let contacts =
            try store.unifiedContacts(matching: predicate, keysToFetch: keysToFetch)
        print("Fetched contacts: \(contacts)")
    } catch {
        print("Failed to fetch contact, error: \(error)")
        // Handle the error
    }
}

์‹คํ–‰ํ•ด๋ณด๋ฉด ์œ„์™€ ๊ฐ™์ด ์˜ค๋ฅ˜๊ฐ€ ๋ฐœ์ƒํ•˜๋Š” ๊ฑธ ๋ณผ ์ˆ˜ ์žˆ๋‹ค. ์™œ๋ƒํ•˜๋ฉด ์—ฐ๋ฝ์ฒ˜๋Š” ๊ฐœ์ธ์ •๋ณด์— ํ•ด๋‹นํ•˜๊ธฐ ๋•Œ๋ฌธ์— ์‚ฌ์šฉ์ž์—๊ฒŒ ๊ถŒํ•œ์„ ์š”์ฒญ๋ฐ›์•„์•ผ ํ•œ๋‹ค.

Contacts ๋ฌธ์„œ ํ•˜๋‹จ์—๋Š” ๊ด€๋ จ๋œ ํ† ํ”ฝ์„ ๋ณผ ์ˆ˜ ์žˆ๋Š”๋ฐ, ์œ„ ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ•˜๋ ค๋ฉด Requesting Authorization to Access Contacts ๋ฌธ์„œ๋ฅผ ๋ณด๋ฉด ๋œ๋‹ค.

์˜์–ด๋งŒ ๋ด๋„ ๋ˆˆ์ด ํ•‘ ๋Œ์•„๊ฐ„๋‹ค. @_@...

์•ฑ์€ ์‚ฌ์šฉ์ž๊ฐ€ ๊ถŒํ•œ์„ ๋ถ€์—ฌํ•  ๋•Œ๊นŒ์ง€ ์—ฐ๋ฝ์ฒ˜ ํ•ญ๋ชฉ์— ์•ก์„ธ์Šค ํ•  ์ˆ˜ ์—†๋‹ค๊ณ  ์„ค๋ช…ํ•˜๋ฉด์„œ ์‚ฌ์šฉ์ž์—๊ฒŒ ์•ก์„ธ์Šค ๊ถŒํ•œ์ด ์žˆ๋Š”์ง€ ํ™•์ธํ•˜๋ ค๋ฉด authorizationStatus(for:) ๋ฉ”์„œ๋“œ๋ฅผ ์‚ฌ์šฉํ•˜๋ผ๊ณ  ์“ฐ์—ฌ์žˆ๋‹ค.

์กฐ๊ธˆ ๋” ๋ฐ‘์œผ๋กœ ๋‚ด๋ ค์„œ ์ฝ์–ด๋ณด๋ฉด, Info.plist ํŒŒ์ผ์— NSContactsUsageDescription ํ‚ค๋ฅผ ์ถ”๊ฐ€ํ•ด์•ผ ํ•œ๋‹ค๊ณ  ์“ฐ์—ฌ์žˆ๋‹ค. ์ด ํ‚ค์˜ ๊ฐ’์€ ์•ฑ์ด ์‚ฌ์šฉ์ž์˜ ์—ฐ๋ฝ์ฒ˜๋กœ ์ˆ˜ํ–‰ํ•˜๋Š” ์ž‘์—…์„ ์„ค๋ช…ํ•˜๋Š” ๋ฌธ์ž์—ด์ด๋ผ๊ณ  ํ•œ๋‹ค.

๊ทธ๋ฆฌ๊ณ  ๊ทธ ๋‹ค์Œ์œผ๋กœ๋Š” ์‚ฌ์šฉ์ž์—๊ฒŒ ๊ถŒํ•œ ์Šน์ธ ์š”์ฒญ์„ ํ•˜๋Š” ๋ฐฉ๋ฒ•์ด ์“ฐ์—ฌ์žˆ๋‹ค. requestAccess(for:completionHandler:) ๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ๋œ๋‹ค๊ณ  ํ•œ๋‹ค. ํ•„์š”ํ•œ ์ •๋ณด๋ฅผ ์ „๋ถ€ ์•Œ์•„๋ƒˆ์œผ๋‹ˆ ๋ฌธ์ œ๋ฅผ ๋ฌธ์„œ์—์„œ ์ œ์‹œํ•˜๋Š” ๋Œ€๋กœ ์•ฑ์„ ์ˆ˜์ •ํ•ด๋ณธ๋‹ค.

๋จผ์ € Info.plist ํŒŒ์ผ์— NSContactsUsageDescription ํ‚ค๋ฅผ ์ถ”๊ฐ€ํ•ด์•ผ ํ•˜๋Š”๋ฐ, ์ด๊ฒƒ๋งŒ ๋ด์„  ๋ญ”์ง€ ๋ชจ๋ฅผ ๊ฑฐ ๊ฐ™์ง€๋งŒ ์• ํ”Œ์—์„  ์นœ์ ˆํ•˜๊ฒŒ ํ•ด๋‹น ํ‚ค๊ฐ€ ์‹ค์ œ๋กœ ๋ฌด์Šจ ์ด๋ฆ„์„ ๊ฐ€์กŒ๋Š”์ง€ ๋ฌธ์„œ๋กœ ์ œ๊ณตํ•˜๊ณ  ์žˆ๋‹ค.

https://developer.apple.com/documentation/bundleresources/information_property_list/nscontactsusagedescription

Info.plist์— ๋‹ค์Œ๊ณผ ๊ฐ™์ด ์ถ”๊ฐ€ํ•ด์ค€๋‹ค. ์‚ฌ์šฉ์ž์—๊ฒŒ ์ด ๊ถŒํ•œ์ด ์™œ ํ•„์š”ํ•œ์ง€ ์„ค๋ช…์„ ๊ธฐ๋กํ•ด์•ผ ํ•œ๋‹ค.

์ด๋ ‡๊ฒŒ ํ•œ ๋‹ค์Œ์— ๋ฐ”๋กœ ์—ฐ๋ฝ์ฒ˜์— ์ ‘๊ทผํ•˜๋Š” ๊ฒŒ ์•„๋‹ˆ๋ผ requestAccess(for:completionHandler:)๋ฅผ ์ด์šฉํ•ด ์‚ฌ์šฉ์ž์—๊ฒŒ ์Šน์ธ ์š”์ฒญ์„ ํ•œ๋‹ค. ๊ถŒํ•œ์ด ์žˆ์œผ๋ฉด ์—ฐ๋ฝ์ฒ˜์— ์ ‘๊ทผํ•˜๊ณ , ์—†์œผ๋ฉด ์‚ฌ์šฉ์ž์—๊ฒŒ ๊ถŒํ•œ ์š”์ฒญ์„ ํ•œ๋‹ค.

let store = CNContactStore()

override func viewDidLoad() {
    super.viewDidLoad()

    self.requestCNContactStoreAccess {
        // ์Šน์ธ ์š”์ฒญ ์„ฑ๊ณต์‹œ ํ•  ์ž‘์—…
        fetchContacts()
        DispatchQueue.main.async {
            self.tableView.reloadData()
        }
    }
}

func requestCNContactStoreAccess(completion: @escaping () -> Void) {
    self.store.requestAccess(for: .contacts) { (granted, error) in
        // ์—๋Ÿฌ ๋ฐœ์ƒ
        if let error = error {
            print(error.localizedDescription)
            return
        }

        // ์‚ฌ์šฉ์ž์—๊ฒŒ ์Šน์ธ ์š”์ฒญ ์„ฑ๊ณต์‹œ ํƒˆ์ถœ
        if granted {
            completion()
        }
    }
}

์ด ๊ณผ์ •์—์„œ fetchContacts์— ์žˆ๋˜ store ๊ฐ์ฒด๋ฅผ ์™ธ๋ถ€๋กœ ๋ณด๋ƒˆ๋‹ค.

requestCNContactStoreAccess ๋ฉ”์„œ๋“œ๋ฅผ ๋งŒ๋“ค๋ฉด์„œ ์ฒ˜์Œ์œผ๋กœ ํƒˆ์ถœ ํด๋กœ์ €๋ฅผ ์‚ฌ์šฉํ•ด๋ดค๋‹ค. ์ด๋ ‡๊ฒŒ ์ž‘์„ฑํ•˜๋‹ˆ ์ฝ”๋“œ๊ฐ€ ๊น”๋”ํ•ด์ ธ์„œ ๊ฐ€๋…์„ฑ์ด ์ข‹์•„์กŒ๋‹ค.

์›๋ž˜๋Š” fetch์™€ request๋ฅผ ๊ฐ™์ด ํ•˜๊ณ  ์žˆ์—ˆ๋Š”๋ฐ ๋ฆฌํŒฉํ† ๋ง์„ ํ•ด์„œ ๋ฉ”์„œ๋“œ๋ฅผ ๋ถ„๋ฆฌํ–ˆ๋‹ค.

์‚ฌ์šฉ์ž ์Šน์ธ ์š”์ฒญ๊ณผ ์—ฐ๋ฝ์ฒ˜ ์ •๋ณด๊นŒ์ง€ ์ž˜ ๊ฐ€์ ธ์˜ค๋Š” ๊ฒƒ์„ ํ™•์ธํ•  ์ˆ˜ ์žˆ๋‹ค.

๊ทธ๋Ÿฐ๋ฐ ์œ„ ์ฝ”๋“œ๋Š” ์ด๋ฆ„์ด "Appleseed"์ธ ์‚ฌ๋žŒ์˜ ์—ฐ๋ฝ์ฒ˜๋งŒ ๊ฐ–๊ณ  ์˜จ๋‹ค. ๋ชจ๋“  ์—ฐ๋ฝ์ฒ˜ ์ •๋ณด๋ฅผ ๊ฐ€์ ธ์˜ฌ ์ˆ˜ ์žˆ๊ฒŒ fetchContacts() ๋ฉ”์„œ๋“œ๋ฅผ ์ˆ˜์ •ํ•ด๋ณด์ž. ๊ทธ๋ฆฌ๊ณ  ๊ฐ€์ ธ์˜จ ์ •๋ณด๋ฅผ CNContact ๋ฐฐ์—ด์— ์ €์žฅํ•œ๋‹ค.

let store = CNContactStore()
var contatcs: Array<CNContact> = []

func fetchContacts() {
    let keysToFetch = [CNContactGivenNameKey, CNContactFamilyNameKey] as [CNKeyDescriptor]
    let request = CNContactFetchRequest(keysToFetch: keysToFetch)

    do {
        try self.store.enumerateContacts(with: request, usingBlock: { (contact, stopPointer) in
            self.contacts.append(contact)
        })
    } catch {
        print("Failed to fetch contact, error: \(error)")
    }
}

์—ฐ๋ฝ์ฒ˜ ์ •๋ณด๋ฅผ ๊ฐ€์ ธ์˜ฌ ๋•Œ ๋ชจ๋“  ์ •๋ณด๋ฅผ ๊ฐ€์ ธ์˜ค๋Š” ๊ฒŒ ์•„๋‹ˆ๋ผ keysToFetch ์— ์žˆ๋Š” ๊ฐ’๋งŒ ๊ฐ–๊ณ  ์˜ค๊ธฐ ๋•Œ๋ฌธ์— ํ•„์š”ํ•œ ๊ฐ’์„ ์ ์–ด์ค˜์•ผ ํ•œ๋‹ค.

๊ทธ๋ฆฌ๊ณ  ์ง„์งœ ๋งˆ์ง€๋ง‰์œผ๋กœ.. ๊ฐ€์ ธ์˜จ ๋ฐ์ดํ„ฐ๋ฅผ ํ…Œ์ด๋ธ”๋ทฐ๋ฅผ ํ†ตํ•ด ๋ฟŒ๋ ค์ค€๋‹ค.

// MARK: - Table view data source
override func numberOfSections(in tableView: UITableView) -> Int {
    // #warning Incomplete implementation, return the number of sections
    return 1
}

override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
    // #warning Incomplete implementation, return the number of rows
    return contacts.count
}

override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
    let cell = tableView.dequeueReusableCell(withIdentifier: "cellIdentifier", for: indexPath)

    let contact = contacts[indexPath.row]
    cell.textLabel?.text = contact.familyName
    cell.detailTextLabel?.text = contact.givenName

    return cell
}

์™„์„ฑ!

์• ํ”Œ ๊ฐœ๋ฐœ์ž ๋ฌธ์„œ๋Š” ์ง„์งœ ์ž˜ ์ •๋ฆฌ๋˜์–ด์žˆ๋‹ค๋Š” ๊ฑธ ๋˜ ํ•œ๋ฒˆ ๋Š๊ผˆ๋‹ค. 

๋ฐ˜์‘ํ˜•