0

I have a PhoneViewController : UIViewController

let phonePage = storyboard.instantiateViewControllerWithIdentifier("phoneViewController") as! PhoneViewController

I am presenting it from 2 different controllers.

// UIViewController1
self.navigationController?.pushViewController(phonePage, animated: true)

// UIViewController2
self.presentViewController(phonePage.embedInNavController(), animated: true, completion: nil)

I would like to have a have to detect which controller was its parent. How would I be able to do that?

Gavin
  • 2,784
  • 6
  • 41
  • 78
  • please have a look at it http://stackoverflow.com/questions/28198638/how-to-get-class-name-of-parent-viewcontroller-in-swift – Nikunj Damani Jan 24 '17 at 09:13
  • Possible duplicate of [How to get class name of parent ViewController in Swift?](http://stackoverflow.com/questions/28198638/how-to-get-class-name-of-parent-viewcontroller-in-swift) – Nikunj Damani Jan 24 '17 at 09:14
  • 1
    Is there a way to inform(tell) the child instead of the child asking for info as stated by the accepted answer? – Gavin Jan 24 '17 at 09:15
  • Did the above comments solve your problem ? Or what exactly would you like to do from the phone viewcontroller ? – Tushar Jan 24 '17 at 09:17
  • how you would like to use it ? – Nikunj Damani Jan 24 '17 at 09:19
  • Not sure what exactly you want to do with that but here is it - Store a reference of the child controller in your parent controller and then invoke a method defined on the child controller form parent controller ... this is the normal way of telling something to the object. – Tushar Jan 24 '17 at 09:21
  • I just needed a way to identify which parentVC presented the childVC. I ended up creating a property on the childVC that the parentVC will set when it pushes the childVC. Not sure if that is a clean fix though – Gavin Jan 24 '17 at 10:03
  • it is a normal way to put properties to the childVC. mostly not a reference but better: if the child VC behaves differently then set the info how the childVC should be layoutet. then it can be called from more parentVC but not need to check each name of the parent controller. if you want something should done: add a closure which is called in this situation. decouple as much as possible to make your childVC reusable and testable (maybe you set mockup dataset to your childVC while testing) – muescha Jan 24 '17 at 10:44
  • look at MVP Pattern very dump views, all data is set by the presenter/user reactions handled by presenter, all interesting user reactions is done by Presenter (done/delete etc) – muescha Jan 24 '17 at 10:52

4 Answers4

0

The short answer is :

if let navController = self.navigationController {
    return navController.viewControllers[navController.viewControllers.count - 1]
    // take care if count <= 1
else {
    return self.parent
}

But is this what you really looking for ? What behavior are you trying to implement based on who is his parent ? I don't have the answer to this question but you should make your code readable. Let me explain by an example :

let phonePage = storyboard.instantiateViewControllerWithIdentifier("phoneViewController") as! PhoneViewController

// Option 1
self.navigationController?.pushViewController(phonePage, animated: true)
phonePage.mode = PhonePageMode.list


// Option 2
self.presentViewController(phonePage.embedInNavController(), animated: true, completion: nil)
phonePage.mode = PhonePageMode.grid

// In your PhoneViewController class
switch self.mode {
    case .list: // present as a list
    case .grid: // present as a grid
}

is more readable than :

let phonePage = storyboard.instantiateViewControllerWithIdentifier("phoneViewController") as! PhoneViewController

// Option 1
self.navigationController?.pushViewController(phonePage, animated: true)

// Option 2
self.presentViewController(phonePage.embedInNavController(), animated: true, completion: nil)

// In your PhoneViewController class
guard let parent = self.parentViewController else { return }
if parent is ThisClassWhichWantsAList {
    // present as list
} else if parent is ThisOtherClassWhichWantsAGrid {
    // present as grid
}

If you want to use its parent as a condition to do things differently, you'd rather use an additional attribute. Your futur self will be thankful.

tgyhlsb
  • 1,905
  • 14
  • 21
  • 1
    There is no parentViewController in swift 3, it is just ```parent```. And if the secondVC is pushed, the parent will be the navigationController. – trusk Jan 24 '17 at 09:29
  • I ended up creating a property on the childVC that the parentVC will set when it pushes the childVC. Not sure if that is a clean fix though – Gavin Jan 24 '17 at 10:02
  • if you only need to know who is its parent, it's the perfect fix. If you want to manipulate the parent or call some functions on it, then `delegation` is the pattern you are looking for – tgyhlsb Jan 24 '17 at 10:06
0

you can try this code:-

if let wd = self.window {
       var vc = wd.rootViewController
       if(vc is UINavigationController){
            vc = (vc as UINavigationController).visibleViewController
        }

        if(vc is YourViewController){
            //your code
        }
    }
Kamal Thakur
  • 398
  • 2
  • 8
0

if your'r view controller is pushed from navigationViewController than parent class in parentViewController available and if presented than in presentationController available.

You can check in this way:

if let parentVC = self.navigationController.parentViewController{
   //parentVC.className

}

if let presentedVC = self.navigationController?.presentationController{
   //presentedVC.className      
}
Sunil Prajapati
  • 473
  • 5
  • 17
-1

So you basically have to check if the view controller in the navigation controller stack, at the index of count - 1 is the kind of view controller that you are looking for.

Short version:

if navigationController.viewControllers[navigationController.viewControllers.count - 1].isKind(of: TheVCYouAreLooking for.self) {
    print("it is")
} else {
    print("it is NOT")
}

Long version from a playground:

//These are your two view controllers
class FirstVCClass: UIViewController {}
class SecondVCClass: UIViewController {}


let vc = FirstVCClass()
let secondVC = SecondVCClass()
//Create a navigationcontroller and add the first VC in the stack
let navigationController = UINavigationController()
navigationController.setViewControllers([vc], animated: true)

//Now push the secondVC
vc.navigationController?.pushViewController(secondVC, animated: true)

//The last vc in the stack is the one you've just pushed
print(navigationController.viewControllers.last!)

// Now check
if navigationController.viewControllers[navigationController.viewControllers.count - 1].isKind(of: FirstVCClass.self) {
    //The view controller that is before you current vc in the stack is of the class 
    print("it is")
} else {
    print("it is NOT")
}
trusk
  • 1,634
  • 2
  • 18
  • 32