Given a view, how do I get its viewController?
Yes, the superview
is the view that contains your view. Your view shouldn't know which exactly is its view controller, because that would break MVC principles.
The controller, on the other hand, knows which view it's responsible for (self.view = myView
), and usually, this view delegates methods/events for handling to the controller.
Typically, instead of a pointer to your view, you should have a pointer to your controller, which in turn can either execute some controlling logic, or pass something to its view.
Get to UIViewController from UIView?
Since this has been the accepted answer for a long time, I feel I need to rectify it with a better answer.
Some comments on the need:
- Your view should not need to access the view controller directly.
- The view should instead be independent of the view controller, and be able to work in different contexts.
- Should you need the view to interface in a way with the view controller, the recommended way, and what Apple does across Cocoa is to use the delegate pattern.
An example of how to implement it follows:
@protocol MyViewDelegate < NSObject >
- (void)viewActionHappened;
@end
@interface MyView : UIView
@property (nonatomic, assign) MyViewDelegate delegate;
@end
@interface MyViewController < MyViewDelegate >
@end
The view interfaces with its delegate (as UITableView
does, for instance) and it doesn't care if its implemented in the view controller or in any other class that you end up using.
My original answer follows: I don't recommend this, neither the rest of the answers where direct access to the view controller is achieved
There is no built-in way to do it. While you can get around it by adding a IBOutlet
on the UIView
and connecting these in Interface Builder, this is not recommended. The view should not know about the view controller. Instead, you should do as @Phil M suggests and create a protocol to be used as the delegate.
Get the parentViewController instance
The fact that it's difficult to get a reference to a view's associated controller should be a hint that it's bad practice. You would be better off passing the parent view controller into the view's initialiser and storing it as a weak reference.
class TheView: UIView {
weak var parentViewController: MyViewController?
init(parentViewController: MyViewController) {
self.parentViewController = parentViewController
}
}
// in MyViewController...
let view = TheView(parentViewController: self)
How do I push a view controller from a UIView
You can't push any controller from UIView. To do this you have to use NavigationController.
I'm assuming you have your UIView inside some UIViewController so one of the many options would be to create a delegate that will tell your view controller to do the push.
protocol MyViewDelegate {
func didTapButton()
}
class MyView: UIView {
weak var delegate: MyViewDelegate?
func buttonTapAction() {
delegate?.didTapButton()
}
}
class ViewController: UIViewController, MyViewDelegate {
override func viewDidLoad() {
super.viewDidLoad()
myView.delegate = self
}
func didTapButton() {
self.navigationController?.pushViewController(someVc, animated: true)
}
}
How would you presentViewController from subview?
You can always use application rootviewController to present your alert view controller :) You dont always have to opt for your view controller's view :) rootview controller is always accessible no matter where your control is :)
Here is what you can do :)
Objective C
AppDelegate *delegate = (AppDelegate *)[[UIApplication sharedApplication] delegate];
[delegate.window.rootViewController presentViewController:your_alert_view_controller animated:YES completion:nil];
Swift
let appDelegate : AppDelegate? = UIApplication.sharedApplication().delegate as? AppDelegate
if let unwrappedAppdelegate = appDelegate {
unwrappedAppdelegate.window!.rootViewController! .presentViewController(alert, animated: true, completion: nil)
}
Hope my answer helped you :)
Find out which view controller you came from
You could use delegation to do this.
You could define a protocol, say, RateViewControllerDelegate
. RateViewController
would have a delegate that conforms to this protocol.
Your PlaceViewController
would conform to this protocol, which could have a method such as -rateViewControllerCompletedSomeThing
, which the RateViewController
could send when it is finished. In PlaceViewController's
implementation of this method, it could dismiss/pop RateViewController
, and do whatever else it is that you want to do when RateViewController
has been dismissed.
How to identify the viewController a button has been added onto?
A view controller is not a view, so it can never be a superview. You have the right idea, but you're looking at the wrong hierarchy. What you want is not the view hierarchy but the responder chain.
Walk up the responder chain until you come to the view controller:
var r : UIResponder = theButton
repeat { r = r.next! } while !(r is UIViewController)
let vc = r as! UIViewController
Get the current displaying UIViewController on the screen in AppDelegate.m
You can use the rootViewController
also when your controller is not a UINavigationController
:
UIViewController *vc = self.window.rootViewController;
Once you know the root view controller, then it depends on how you have built your UI, but you can possibly find out a way to navigate through the controllers hierarchy.
If you give some more details about the way you defined your app, then I might give some more hint.
EDIT:
If you want the topmost view (not view controller), you could check
[[[[UIApplication sharedApplication] keyWindow] subviews] lastObject];
although this view might be invisible or even covered by some of its subviews...
again, it depends on your UI, but this might help...
Related Topics
Behaviour for Significant Change Location API When Terminated/Suspended
How to Create a Delay in Swift
"From View Controller" Disappears Using Uiviewcontrollercontexttransitioning
How to Get the Console Logs from the iOS Simulator
Uitextview That Expands to Text Using Auto Layout
Remove Gradient Background from Uiwebview
iOS 7 -- Navigationcontroller Is Setting the Contentinset and Contentoffset of My Uiscrollview
How to Make a Uilabel Clickable
Custom Mkannotation Callout Bubble with Button
Linker Command Failed with Exit Code 1 (Use -V to See Invocation), Xcode 8, Swift 3
Xcode Stuck at "Your Application Is Being Uploaded"
iOS 8 - Can't Install Enterprise App
Difference Between Protocol and Delegates
How to Check If a View Controller Is Presented Modally or Pushed on a Navigation Stack
Chain Multiple Alamofire Requests
Module Compiled with Swift 5.1 Cannot Be Imported by the Swift 5.1.2 Compiler
iOS Perform Action After Period of Inactivity (No User Interaction)