允许 SwiftUI 导入所有联系人并删除特定联系人

Allowing SwiftUI to import all Contacts and delete specific ones

请原谅我的知识匮乏,我正在尝试制作我的第一个 iOS 应用程序,我的目标是将我所有的联系人导入到 swiftui 视图中:

//ContentView.swift
import SwiftUI

struct ContentView: View {
    var contact = contactData
    @ObservedObject var contacts = ContactList()

    var body: some View {
        NavigationView {
            List {
                ForEach(contact) { item in
                    VStack(alignment: .leading) {
                        HStack {
                            Text(item.contactName)
                        }
                    }
                }
                .onDelete { index in
                    self.contacts.contact.remove(at: index.first!)
                }
            }
            .navigationBarTitle(Text("Contacts"))
            .navigationBarItems(
                trailing: EditButton()
            )
        }
    }
}

#if DEBUG
struct ContentView_Previews: PreviewProvider {
    static var previews: some View {
        ContentView()
    }
}
#endif

struct Contacts: Identifiable {
    var id = UUID()
    var contactName: String
}

let contactData = [
    Contacts(contactName: "Foo Bar"),
    Contacts(contactName: "Johnny Appleseed")
]

//ContactList.swift
import Combine

class ContactList: ObservableObject {
    @Published var contact: [Contacts] = contactData
}

使用 Combine API 和 .onDelete 功能,我想删除多个联系人(目前 iOS 中没有此功能),然后 return 他们回来进入通讯录应用程序。

虽然我无法拉入联系人列表,但我尝试了多种不同的方法来使用 Swift,例如:

var contacts = [CNContact]()
let keys = [CNContactFormatter.descriptorForRequiredKeysForStyle(.FullName)]
let request = CNContactFetchRequest(keysToFetch: keys)

do {
    try self.contactStore.enumerateContactsWithFetchRequest(request) {             
        (contact, stop) in
        // Array containing all unified contacts from everywhere
        contacts.append(contact)
    }
} 
catch {
    print("unable to fetch contacts")
}

但是如果不抛出一堆错误,那似乎无法正常工作。我现在不太担心删除,但主要关注导入联系人。

有人知道使用 SwiftUI 和联系人 API 是否有好的方法吗?或者至少可以指出我正确的方向?我知道我正在使用 Xcode 11 Beta 5,这可能会导致不同 API 的弃用问题,但联系人 API 在 [=29 中似乎相对没有变化=] 11.

您通常使用 ObservableObject 进行 model/controller 互动。发布它们只允许我将结果分配给变量。

它目前在 onAppear 异步开始获取,否则它会阻止 UI 加载并且请求联系人将无法工作。

缺少的是更好的授权处理(参见 this), deletion/creation、刷新(在其他地方调用 fetch)和更全面的功能。

条件 允许我向联系人显示 错误,这有助于快速发现错误。

注意:您必须在 info.plist 中添加隐私联系人说明,以免崩溃。它应该在不改变任何其他东西的情况下工作。

注 2:由于 SwiftUI 只有接线和 UI 更改为@dfd说。如何检索联系人仍然完全一样。

import Contacts
import SwiftUI
import os

class ContactStore: ObservableObject {
    @Published var contacts: [CNContact] = []
    @Published var error: Error? = nil

    func fetch() {
        os_log("Fetching contacts")
        do {
            let store = CNContactStore()
            let keysToFetch = [CNContactGivenNameKey as CNKeyDescriptor,
                               CNContactMiddleNameKey as CNKeyDescriptor,
                               CNContactFamilyNameKey as CNKeyDescriptor,
                               CNContactImageDataAvailableKey as CNKeyDescriptor,
                               CNContactImageDataKey as CNKeyDescriptor]
            os_log("Fetching contacts: now")
            let containerId = store.defaultContainerIdentifier()
            let predicate = CNContact.predicateForContactsInContainer(withIdentifier: containerId)
            let contacts = try store.unifiedContacts(matching: predicate, keysToFetch: keysToFetch)
            os_log("Fetching contacts: succesfull with count = %d", contacts.count)
            self.contacts = contacts
        } catch {
            os_log("Fetching contacts: failed with %@", error.localizedDescription)
            self.error = error
        }
    }
}

extension CNContact: Identifiable {
    var name: String {
        return [givenName, middleName, familyName].filter{ [=10=].count > 0}.joined(separator: " ")
    }
}

struct ContactsView: View {
    @EnvironmentObject var store: ContactStore

    var body: some View {
        VStack{
            Text("Contacts")
            if store.error == nil {
                List(store.contacts) { (contact: CNContact) in
                    return Text(contact.name)
                }.onAppear{
                    DispatchQueue.main.async {
                        self.store.fetch()
                    }
                }
            } else {
                Text("error: \(store.error!.localizedDescription)")
            }
        }
    }
}

struct ContactsViewOrError: View {
    var body: some View {
        ContactsView().environmentObject(ContactStore())
    }
}