23

Is there any way to get class name of parent VC in present (child) UIViewController? My 'child' VC (push) has two 'parent'UIViewControllers, so I would like to know which one is current parent?

Cesare
  • 9,139
  • 16
  • 78
  • 130
Marko
  • 2,021
  • 4
  • 16
  • 18

7 Answers7

31

Here's one approach:

if let parentVC = parent as? SomeViewController {
    // parentVC is someViewController
} else if let parentVC = parent as? AnotherViewController {
    // parentVC is anotherViewController
}

This will conditionally assign and unwrap parent (the parent view controller) to its appropriate type. Within the condition blocks, parentVC will be the correct class.

That said, this is a code smell - child view controllers should typically have no idea who their parent view controllers are. Whatever problem you're solving, you should probably solve it with tell, don't ask and delegation instead.

Aaron Brager
  • 65,323
  • 19
  • 161
  • 287
  • It seems like good and right way to do that, but for some reason value of parentViewController in my pushed child-VC is always nil. So I did that on a dumb way: had to make Int variable _parentIndicator_ in child-VC, and I'm passing some value to it from parent controllers (using delegation and prepareForSegue). – Marko Jan 29 '15 at 10:19
  • 1
    Update answer to swift 4! In swift for you should use parentVC is someViewController instead of your code!!! – Shahen Kosyan Jan 29 '19 at 10:57
  • 1
    If we used `is` then we wouldn’t get the type binding inside the conditional bracket – Aaron Brager Jan 29 '19 at 21:02
  • Note: 'parentViewController' has been renamed to 'parent' – iPhoneDeveloper Aug 04 '22 at 14:23
12

UPDATED TO SWIFT 5

In your child view controller, you could try something like:

guard let parent = self.presentingViewController else{
    // ...some code
    return
}
//presented by parent view controller 1
if parent.isKind(of: Parent1.self){
    // do something
}else{
    //presented by parent view controller 2
}

I recommend you to place this logic in your viewWillAppear method because when viewDidLoad is called, there is no guarantee that the view controller hierarchy is loaded in the navigation tree and like a consequence of this, the presentingViewController property of your child view controller might be nil

mauricioconde
  • 5,032
  • 3
  • 28
  • 24
  • 1
    Why not use `as?` or `is`? Also, this will cause a crash if `presentingViewController` is `nil`. – Aaron Brager Jan 28 '15 at 23:28
  • 1
    i just tried to show another way to approach, and you're right, everything could be inside the `if(self.presentingViewController != nil)` statement. Thanks for the feedback! – mauricioconde Jan 30 '15 at 17:33
4

First add extension in view controller

extension UIView {
    var parentViewController: UIViewController? {
        var parentResponder: UIResponder? = self
        while parentResponder != nil {
            parentResponder = parentResponder!.next
            if let viewController = parentResponder as? UIViewController {
                return viewController
            }
        }
        return nil
    }
}

Now Use it Like this

let vc = self.parentViewController

or

if let parentVC = self.parentViewController {
    if let parentVC = parentVC as? someViewController {
        // parentVC is someViewController
    } else if let parentVC = parentVC as? anotherViewController {
        // parentVC is anotherViewController
    }
}
EstevaoLuis
  • 2,422
  • 7
  • 33
  • 40
Kavin Soni
  • 101
  • 1
  • 3
2

try to pick the child from the children array as following

if let parentVC = self.parent {

            if let parentVC = parentVC.children[0] as? someViewController {}}
Yosra Nagati
  • 780
  • 2
  • 8
  • 26
  • Never know there exist a property named Children. This was usefull when we assign one viewcontroller view to another viecontroller – Sujananth Apr 20 '23 at 17:18
1

Simply use view.parentViewController and eventually its title property.

qwerty_so
  • 35,448
  • 8
  • 62
  • 86
  • 1
    The OP asked for its class, not its title. – Aaron Brager Jan 28 '15 at 18:00
  • 1
    Ah yes. But one could use the title to distinguish both ;-) – qwerty_so Jan 28 '15 at 18:01
  • This is quite unreliable (since the `title` property is purely optional for `UIViewControllers`), and a flat out wrong answer to this particular question since the title property will NEVER return the class name (unless you're explicitly assigning it, which is also quite pointless most of the time...) – Priest Nov 14 '17 at 03:58
  • @Priest Just see it as an alternative to distinguish things, not more. I posted this a bit before the accepted answer which is getting more to the point (`parentController`). – qwerty_so Nov 14 '17 at 07:17
0

Updated to Swift 4

Swift 4:

if let parentVC = self.parent {
    if parentVC is someViewControllerr {
        // parentVC is someViewController
    } else if parentVC is anotherViewController {
        // parentVC is anotherViewController
    }
}

Swift 3:

if let parentVC = self.parentViewController {
    if let parentVC = parentVC as? someViewController {
        // parentVC is someViewController
    } else if let parentVC = parentVC as? anotherViewController {
        // parentVC is anotherViewController
    }
}
Marvin Ruciński
  • 351
  • 3
  • 12
0

Add this extension and find parent view by it's type.

extension UIResponder {
    
    func next<T: UIResponder>(_ type: T.Type) -> T? {
        return next as? T ?? next?.next(type)
    }
    
}

How to use

self.next(UIViewController.self)
Alizain Prasla
  • 744
  • 2
  • 15
  • 37