I have a pointer to a UIView
. How do I access its UIViewController
? [self superview]
is another UIView
, but not the
For debug purposes only, you can call _viewDelegate
on views to get their view controllers. This is private API, so not safe for App Store, but for debugging it is useful.
Other useful methods:
_viewControllerForAncestor
- get the first controller that manages
a view in the superview chain. (thanks n00neimp0rtant)_rootAncestorViewController
- get the ancestor controller whose
view hierarchy is set in the window currently.If you are not familiar with the code and you want to find ViewController coresponding to given view, then you can try:
po (UIView *)0x7fe523bd3000 po [(UIView *)0x7fe523bd3000 nextResponder] po [[(UIView *)0x7fe523bd3000 nextResponder] nextResponder] po [[[(UIView *)0x7fe523bd3000 nextResponder] nextResponder] nextResponder] ...
In most cases you will get UIView, but from time to time there will be UIViewController based class.
To get reference to UIViewController having UIView, you could make extension of UIResponder (which is super class for UIView and UIViewController), which allows to go up through the responder chain and thus reaching UIViewController (otherwise returning nil).
extension UIResponder {
func getParentViewController() -> UIViewController? {
if self.nextResponder() is UIViewController {
return self.nextResponder() as? UIViewController
} else {
if self.nextResponder() != nil {
return (self.nextResponder()!).getParentViewController()
}
else {return nil}
}
}
}
//Swift 3
extension UIResponder {
func getParentViewController() -> UIViewController? {
if self.next is UIViewController {
return self.next as? UIViewController
} else {
if self.next != nil {
return (self.next!).getParentViewController()
}
else {return nil}
}
}
}
let vc = UIViewController()
let view = UIView()
vc.view.addSubview(view)
view.getParentViewController() //provide reference to vc
@andrey answer in one line (tested in Swift 4.1):
extension UIResponder {
public var parentViewController: UIViewController? {
return next as? UIViewController ?? next?.parentViewController
}
}
usage:
let vc: UIViewController = view.parentViewController
Alas, this is impossible unless you subclass the view and provide it with an instance property or alike which stores the view controller reference inside it once the view is added to the scene...
In most cases - it is very easy to work around the original problem of this post as most view controllers are well-known entities to the programmer who was responsible for adding any subviews to the ViewController's View ;-) Which is why I guess that Apple never bothered to add that property.
I think you can propagate the tap to the view controller and let it handle it. This is more acceptable approach. As for accessing a view controller from its view, you should maintain a reference to a view controller, since there is no another way. See this thread, it might help: Accessing view controller from a view