Open a CNContactViewController and edit a contact

I am trying to allow the user to edit a contact that is defined by the contacts identifier.


The contacts identifier is in - private var theContactID: String = ""


This code opens the CNContactViewController but I don't know how to tell the controller to open the specified contact for editing. I appreciate any help.


private var theContactID: String = ""
let theAlert = UIAlertController(title: NSLocalizedString("ContactNoAddress_String", comment: ""), message: nil, preferredStyle: .alert)
                let cancelBtn = UIAlertAction(title: NSLocalizedString("OK_String", comment: ""), style: .cancel) { (cancelAction) in
                    self.populateThePrintFld()
                }
               
                let editBtn = UIAlertAction(title: NSLocalizedString("EditContact_String", comment: ""), style: .default) { (editAction) in
                   
                    self.requestAccess { (accessGranted) in
                        let editContact = CNMutableContact()
                        let vc = CNContactViewController(for: editContact)
                       
                        vc.allowsEditing = true
                       
                        vc.delegate = self // delegate for CNContactViewControllerDelegate
                        DispatchQueue.main.async {
                            self.present(UINavigationController(rootViewController: vc), animated: true)
                        }
                    }
                }
               
                theAlert.addAction(cancelBtn)
                theAlert.addAction(editBtn)
               
                present(theAlert, animated: true)
Answered by OOPer in 414866022

To open `CNContactViewController` for editing an existing contact, you need to pass an existing contact to the initializer.

For example:

        do {
            let descriptor = CNContactViewController.descriptorForRequiredKeys()
            let editContact = try store.unifiedContact(withIdentifier: theContactID, keysToFetch: [descriptor])
            let vc = CNContactViewController(for: editContact)
            //...
        } catch {
            print(error)
        }
Accepted Answer

To open `CNContactViewController` for editing an existing contact, you need to pass an existing contact to the initializer.

For example:

        do {
            let descriptor = CNContactViewController.descriptorForRequiredKeys()
            let editContact = try store.unifiedContact(withIdentifier: theContactID, keysToFetch: [descriptor])
            let vc = CNContactViewController(for: editContact)
            //...
        } catch {
            print(error)
        }

Thanks again, OOPer.


Just in case others have he same requirment, here's the code I ended up with.


let theAlert = UIAlertController(title: NSLocalizedString("ContactNoAddress_String", comment: ""), message: nil, preferredStyle: .alert)
let cancelBtn = UIAlertAction(title: NSLocalizedString("OK_String", comment: ""), style: .cancel) { (cancelAction) in
    self.populateThePrintFld()
}
               
let editBtn = UIAlertAction(title: NSLocalizedString("EditContact_String", comment: ""), style: .default) { (editAction) in
                   
    self.requestAccess { (accessGranted) in
        let store = CNContactStore()
        var vc = CNContactViewController()
            do {
                let descriptor = CNContactViewController.descriptorForRequiredKeys()
                let editContact = try store.unifiedContact(withIdentifier: self.theContactID, keysToFetch: [descriptor])
                vc = CNContactViewController(for: editContact)
            } catch {
                print("Getting contact to edit failed: \(error)")
            }
                       
            vc.allowsEditing = true
                       
            vc.delegate = self // delegate for CNContactViewControllerDelegate
            DispatchQueue.main.async {
                self.present(UINavigationController(rootViewController: vc), animated: true)
            }
        }
    }
               
    theAlert.addAction(cancelBtn)
    theAlert.addAction(editBtn)
               
    present(theAlert, animated: true)


extension QuotePreview_VC: CNContactViewControllerDelegate
{
    func contactViewController(_ viewController: CNContactViewController, didCompleteWith contact: CNContact?)
    {
        // Edit an existing contact with ID theContactID
        populateThePrintFld()
   
        self.dismiss(animated: true, completion: nil)
    }
}

I have a simple follow-on question. When the CNContactViewController opens it has a rightBarButtonItem set to Edit. How do I add a rightBarButtonItem to Cancel ie. dismiss the CNContactViewController?

Sorry, but I do not know much about how to customize CNContactViewController.

One thing sure which does work as expected would be your own view controller editing a contact.

Thanks. I appreciate that.


Seems strange that in a select a contact CNContactPickerViewController() and a create a contact CNContactViewController(forNewContact: openContact) both show cancel buttons. And in the contacts app, if you manually edit a contact, it shows a back button. It's odd that it doesn't automatically show up on the edit a contact CNContactViewController(for: editContact).

Here's what I ended up doing. It dosen't give a cancel button but it does show a back button, which in my case works ok.



let editBtn = UIAlertAction(title: NSLocalizedString("EditContact_String", comment: ""), style: .default) { (editAction) in
           
            self.requestAccess { (accessGranted) in
                let store = CNContactStore()
                var vc = CNContactViewController()
                do {
                    let descriptor = CNContactViewController.descriptorForRequiredKeys()
                    let editContact = try store.unifiedContact(withIdentifier: self.oldContactID, keysToFetch: [descriptor])
                    vc = CNContactViewController(for: editContact)
                } catch {
                    print("Getting contact to edit failed: \(error)")
                }
               
                vc.delegate = self // delegate for CNContactViewControllerDelegate
                // vc.allowsActions = false
                // vc.allowsEditing = true
                // vc.title = "Edit Contact"
               
                self.navigationController?.isNavigationBarHidden = false
                self.navigationController?.navigationItem.hidesBackButton = false
                self.navigationController?.pushViewController(vc, animated: true)
               
                // DispatchQueue.main.async {
                //  self.present(UINavigationController(rootViewController: vc), animated: true)
                // }
            }
        }
Open a CNContactViewController and edit a contact
 
 
Q