0

I am trying to emulate the iOS contacts segueing between two view controllers.

I have a simple Person class given by:

class Person {
    var name = ""
}

and a UIViewController that contains an array of Person, which is embedded in a UINavigationController:

class PeopleViewController: UIViewController {

    var people = [Person]()
    var selectedPerson: Person?

    switch segueIdentifier(for: segue) {
    case .showPerson:
        guard let vc = segue.destination as? PersonViewController else { fatalError("!") }
        vc.person = selectedPerson 
    }

}

This controller uses a Show segue to PersonViewController to display the selectedPerson:

class PersonViewController: UIViewController {
    var person: Person!
}

PeopleViewController can also add a new Person to the array of Person. The NewPersonViewController is presented modally, however:

class NewPersonViewController: UIViewController {
    var person: Person?
}

If a new Person is added, I want NewPersonViewController to dismiss but show the new Person in the PersonViewController that is part of the navigation stack. My best guess for doing this is:

extension NewPersonViewController {
    func addNewPerson() {
        weak var pvc = self.presentingViewController as! UINavigationController
        if let cvc = pvc?.childViewControllers.first as? PeopleViewController {
            self.dismiss(animated: false, completion: {
                cvc.selectedPerson = self.person
                cvc.performSegue(withIdentifier: .showPerson, sender: nil)
            }
        }
    }
}

However, (1) I'm not too happy about forcing the downcast to UINavigationController as I would have expected self.presentingViewController to be of type PeopleViewController? And (2), is there a memory leak in the closure as I've used weak var pvc = self.presentingViewController for pvc but not for cvc? Or, finally (3) is there a better way of doing this?

Many thanks for any help, suggestions etc.

ajrlewis
  • 2,968
  • 3
  • 33
  • 67
  • If you're building a contact list type thing, wouldn't it be best to use a tableview controller? The way I would do is just like the Contact list. Use plus sign button and popup up the Add Contact view controller, then if you want to save it, add a done button commit to the database (i.e. the list of people). Dismiss the Add Contact vc and when you go back to the table view, reload the data. – u84six May 29 '18 at 22:37
  • @u84six Hi thanks for your suggestion. I am using a table view to represent the `people` array. When you click a `Person` in the table view it becomes the selected Person and segues to the `PersonViewController`. I want to segue from the `NewPersonViewController` directly to the `PersonViewController` when the "done" button is clicked. – ajrlewis May 29 '18 at 22:45

1 Answers1

0

(1) I'm not too happy about forcing the downcast to UINavigationController as I would have expected self.presentingViewController to be of type PeopleViewController?

There is nothing wrong in downcasting. I would definitely remove force unwrapping.

(2), is there a memory leak in the closure as I've used weak var pvc = self.presentingViewController for pvc but not for cvc?

I think, there is none.

(3) is there a better way of doing this?

You can present newly added contact from NewContactVC. When you about to dismiss, call dismiss on presentingVC.

// NewPersonViewController.swift
func addNewPerson() {
// New person is added
// Show PeopleViewController modally
}

Note: Using presentingViewController this way will dismiss top two/one Modal(s). You will see only top view controller getting dismissed. If you can't determine how many modals going to be, you should look-into different solution or possibly redesigning navigation flow.

// PeopleViewController.swift
func dismiss() {
    if let presentingVC = self.presentingViewController?.presentingViewController {
       presentingVC.dismiss(animated: true, completion: nil)
    } else {
       self.dismiss(animated: true, completion: nil)
    }
}
k-thorat
  • 4,873
  • 1
  • 27
  • 36
  • Thanks for your answer. Do you know **why** the `presentingViewController` is a `UINavigationController` rather than a `PeopleViewController`, please? – ajrlewis May 29 '18 at 23:25
  • @Alex when you present view, it is presented from root view controller. If you are using tabs, it will be tabviewcontrollers as it is rootviewcontroller – k-thorat May 30 '18 at 00:32