Given a view, how do I get its viewController?

后端 未结 13 590
北海茫月
北海茫月 2020-11-28 02:00

I have a pointer to a UIView. How do I access its UIViewController? [self superview] is another UIView, but not the

相关标签:
13条回答
  • 2020-11-28 02:46

    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.
    0 讨论(0)
  • 2020-11-28 02:46

    If you are not familiar with the code and you want to find ViewController coresponding to given view, then you can try:

    1. Run app in debug
    2. Navigate to screen
    3. Start View inspector
    4. Grab the View you want to find (or a child view even better)
    5. From the right pane get the address (e.g. 0x7fe523bd3000)
    6. In debug console start writing commands:
        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.

    0 讨论(0)
  • 2020-11-28 02:47

    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
    
    0 讨论(0)
  • 2020-11-28 02:48

    @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
    
    0 讨论(0)
  • 2020-11-28 02:48

    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.

    0 讨论(0)
  • 2020-11-28 02:49

    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

    0 讨论(0)
提交回复
热议问题