Search code examples
iosswiftcncontactpicker

CNContactPickerViewController enable to disable multiple selection


I want to enable or disable multiple contact selection based to condition.

I have tried below solution

func onClickPickContact() {
        let contactPicker = CNContactPickerViewController()
        contactPicker.delegate = self
        contactPicker.displayedPropertyKeys =
            [CNContactGivenNameKey
                , CNContactPhoneNumbersKey]
        self.present(contactPicker, animated: true, completion: nil)
    }

func contactPicker(_ picker: CNContactPickerViewController, didSelect contact: CNContact) {
        self.txtFieldFirstname.text = contact.givenName
        self.txtFieldLastname.text = contact.familyName
    }

This allows me to select multiple contacts but I want both the cases (single selection or multiple selection based on condition).

Once the above delegate method is added it is not allowing to select single contact only.

Please Let me know if anyone knows the solution. Thanks in advance.


Solution

  • The behavior you described is correct, because the implemented delegate allows you only one mode. If you try to implement both single and multiple contact selection at the same time, you will get a warning at run time. And this is exactly your case.

    [CNUI WARN] Both single contact and multiple contacts delegate methods are implemented, the single variants will be ignored

    If you want to choose between them, then you need two delegates implementations, one for single selection and another one for multiple selection. Please checkout the solution below:

    import UIKit
    import ContactsUI
    
    class ViewController: UIViewController {
        private var singleSelectionDelegate = SingleSelectionDelegate()
        private var multipleSelectionDelegate = MultipleSelectionDelegate()
        
        var isMultipleSelectionAllowed = false
        var selectionDelegate: (SelectionDelegate & CNContactPickerDelegate) {
            return isMultipleSelectionAllowed ? multipleSelectionDelegate : singleSelectionDelegate
        }
        
        override func viewDidLoad() {
            super.viewDidLoad()
            // Do any additional setup after loading the view.
            
            singleSelectionDelegate.onContactsSelected = didSelect(contacts:)
            multipleSelectionDelegate.onContactsSelected = didSelect(contacts:)
        }
        
        @IBAction func onVerify() {
            let contactPicker = CNContactPickerViewController()
            contactPicker.delegate = selectionDelegate
            contactPicker.displayedPropertyKeys = [CNContactGivenNameKey, CNContactPhoneNumbersKey]
            self.present(contactPicker, animated: true, completion: nil)
        }
        
        @IBAction func onConditionsChanged(segmentedControl: UISegmentedControl) {
            isMultipleSelectionAllowed = segmentedControl.selectedSegmentIndex == 1
        }
        
        func didSelect(contacts: [CNContact]) {
            print("current mode is \(isMultipleSelectionAllowed ? "'single selection'" : "'multiple selection'")")
            print("selected contacts = \(contacts)")
        }
    }
    
    class SelectionDelegate: NSObject {
        var onContactsSelected: (([CNContact]) -> Void)?
    }
    
    class SingleSelectionDelegate: SelectionDelegate, CNContactPickerDelegate {
        func contactPicker(_ picker: CNContactPickerViewController, didSelect contact: CNContact) {
            onContactsSelected?([contact])
        }
    }
    
    class MultipleSelectionDelegate: SelectionDelegate, CNContactPickerDelegate {
        func contactPicker(_ picker: CNContactPickerViewController, didSelect contacts: [CNContact]) {
            onContactsSelected?(contacts)
        }
    }
    

    Now there are two delegates and you switch between them depending on your conditions.