Search code examples
iosswiftcontacts

Move to new view after contact is select from CNContactPickerViewController


I'm writing a concept chat app. I'm now at the point where a new chat could be started.

What I want is that when the user selects a contact using the CNContactPickerViewController, the picker is dismissed (this is working) and the contact details are send to a new chat view (this is not working). The error I get is that at func contactPicker the delegate returns nil. I have been following this tutorial in getting contact data from the ChatsViewController to the ChatViewController. The relevant code:

import UIKit
import Contacts
import ContactsUI

class ChatsViewController: UITableViewController, CNContactPickerDelegate {
    var chats:[Chat] = chatData
    var selectedContact: CNContact = CNContact()
    @IBAction func createNewChat(sender: AnyObject) {
        let contactPickerViewController = CNContactPickerViewController()
        contactPickerViewController.delegate = self
        presentViewController(contactPickerViewController, animated: true, completion: nil)
    }
    
    override func viewDidLoad() {
        super.viewDidLoad()
        // Uncomment the following line to preserve selection between presentations
        // self.clearsSelectionOnViewWillAppear = false
        // Uncomment the following line to display an Edit button in the navigation bar for this view controller.
        // self.navigationItem.rightBarButtonItem = self.editButtonItem()
    }
    
    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
        // Dispose of any resources that can be recreated.
    }
    
    // MARK: - Table view data source
    
    override func numberOfSectionsInTableView(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 chats.count
    }
    
    override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
        let cell = tableView.dequeueReusableCellWithIdentifier("ChatCell", forIndexPath: indexPath) as! ChatCell
        
        let chat = chats[indexPath.row] as Chat
        cell.chat = chat
        return cell
    }
    
    func contactPicker(picker: CNContactPickerViewController, didSelectContact contact: CNContact) {
        self.selectedContact = contact
        self.performSegueWithIdentifier("idContactSelected", sender: self)
    }
    
    override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
        if segue.identifier == "idContactSelected" {
            let chatVC = segue.destinationViewController as! ChatViewController
            chatVC.contact = self.selectedContact
        }
    }
}

And this is the new chat ViewController.

import UIKit
import Contacts
import ContactsUI

class ChatViewController: UIViewController {
    
    @IBOutlet weak var testLabel: UILabel!
    var contact: CNContact = CNContact()
    
    override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view.
        self.testLabel.text = contact.givenName
    }
    
    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
        // Dispose of any resources that can be recreated.
    }
}

So in recap: I have a ViewController, I can press a button there to start a new chat, which opens the contact picker. Once a contact is selected, the func contactPicker is executed, but the contact data is never sent, nor the new chat ViewController is presented and the delegate is nil. Why is this happening? I assume it is because delegate is never set, only created, but in the tutorial this is all they do and it seems to work.

Thanks in advance for any thoughts on this.

EDIT: Solution in the end: I didn't need the delegate, I can just push data through prepareForSegueWithIdentifier. Also, the segue was not connected properly, reconnecting the segue fixed the transition not working.


Solution

  • Try some thing like this. Change your code something like this

    ChatsViewController

    import UIKit
    import Contacts
    import ContactsUI
    
    class ChatsViewController: UITableViewController, CNContactPickerDelegate {
        var chats:[Chat] = chatData
        var selectedContact: CNContact = CNContact()
        @IBAction func createNewChat(sender: AnyObject) {
            let contactPickerViewController = CNContactPickerViewController()
            contactPickerViewController.delegate = self
            presentViewController(contactPickerViewController, animated: true, completion: nil)
        }
    
        override func viewDidLoad() {
            super.viewDidLoad()
            // Uncomment the following line to preserve selection between presentations
            // self.clearsSelectionOnViewWillAppear = false
            // Uncomment the following line to display an Edit button in the navigation bar for this view controller.
            // self.navigationItem.rightBarButtonItem = self.editButtonItem()
        }
    
        override func didReceiveMemoryWarning() {
            super.didReceiveMemoryWarning()
            // Dispose of any resources that can be recreated.
        }
    
        // MARK: - Table view data source
    
        override func numberOfSectionsInTableView(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 chats.count
        }
    
        override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
            let cell = tableView.dequeueReusableCellWithIdentifier("ChatCell", forIndexPath: indexPath) as! ChatCell
    
            let chat = chats[indexPath.row] as Chat
            cell.chat = chat
            return cell
        }
    
        func contactPicker(picker: CNContactPickerViewController, didSelectContact contact: CNContact) {
             self.selectedContact = contact
             self.performSegueWithIdentifier("idContactSelected", sender: self)
        }
    
        override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
             if segue.identifier == "idContactSelected" {
                 let chatVC = segue.destinationViewController as! ChatViewController
                 chatVC.contact = self.selectedContact
             }
        }
    }
    

    After that change your ChatViewController

    import UIKit
    import Contacts
    import ContactsUI
    class ChatViewController: UIViewController {
    
         @IBOutlet weak var testLabel: UILabel!
         var contact: CNContact = CNContact()
    
         override func viewDidLoad() {
             super.viewDidLoad()
             // Do any additional setup after loading the view.
             self.testLabel.text = contact.givenName
         }
    
         override func didReceiveMemoryWarning() {
             super.didReceiveMemoryWarning()
             // Dispose of any resources that can be recreated.
         }
    }
    

    Hope this will help you.