I have only one window and I tried
UIWindow* mWindow = [[UIApplication sharedApplication] keyWindow];
but this returned nil.
I also tried:
UIWindow* mWindow = (UIWindow*)[[UIApplication sharedApplication].windows objectAtIndex:0];
But this raised an exception and the app closed, when I tried to print out
[[UIApplication sharedApplication].windows count]
It printed 0
Note: I am putting this in my only view controller's viewDidLoad method and this is completely a new iPad View Based Application so I changed nothing, just trying to get the window
Please help me to get this object
If your main window is an outlet of your AppDelegate (which should be the case), you may simply use
MyAppDelegate* myDelegate = (((MyAppDelegate*) [UIApplication sharedApplication].delegate));
[myDelegate.window ...]
Easiest way is to get the window from the app delegate instead:
UIWindow *keyWindow = [[[UIApplication sharedApplication] delegate] window];
// Do something with the window now
Your application's key window isn't set until [window makeKeyAndVisible] gets called in your app delegate. Your UIViewController is probably being loaded from a NIB before this call. This explains why keyWindow is returning nil.
Luckily, your view controller doesn't need to go through UIApplication to get the window. You can just do:
UIWindow *mWindow = self.view.window;
[[[UIApplication sharedApplication] windows] objectAtIndex:0]; // You can also check the count of this to make sure, because if there are no windows it will crash.
With iOS 13+ you should use:
if let currentScene = UIApplication.shared.connectedScenes.first as? UIWindowScene,
let window = currentScene.keyWindow {
// now window contains the active window
}
You can achieve this in multiple ways. I like to use one of the following.
Use this when you need to access it just once.
if let window = UIApplication.shared.windows.first as UIWindow? {
// Action
}
If you need to access the UIWindow multiple times, I would suggest extending a class. I like to extend the UIViewController.
extension UIViewController {
/// Returns the UIWindow if available.
public var window: UIWindow? {
UIApplication.shared.windows.first as UIWindow?
}
}
Related
We have a requirement to change UIDocumentInteractionController preview screen? Is it possible to change the rect of UIDocumentInteractionController? I want to open document preview in my custom view?
in creating an AIR Native Extension, I needed to create a view window for my custom view controller.
make sure you are doing:
#import "MyCustomViewController.h"
in my function:
MyCustomViewController *myViewController;
id delegate = [[UIApplication sharedApplication] delegate];
UIWindow *win = [delegate window];
myViewController = [[MyCustomViewController alloc]init];
[win addSubview:myViewController.view];
[myViewController previewDocument: (parameters to method)];
return (_bridge FREObject)(myViewController);
where you implement this may be different depending on your structure. Since I am using it as an ANE, I put it right into the Context function call.
hope it gives you a starting point if you haven't gotten it yet.
I have this bool function in my app delegate that I am trying to return to no on a certain view controller. Here is the code I have in my view controller, no error but it doesn't return the bool "switch" to no.
[(Appdelegate*)[[UIApplication sharedApplication] delegate]switch];
If switch is a property in your app delegate, you're not assigning a value to it. For example:
[(Appdelegate*)[[UIApplication sharedApplication] delegate] switch];
Will compile with no errors, but it isn't doing anything.
The following would set the bool property switch to NO:
Appdelegate* appDelegate = (Appdelegate*)[[UIApplication sharedApplication] delegate];
appDelegate.switch = NO;
If switch is a method, again your code will compile with no errors, but it won't set a bool in the app delegate.
I have a TabBarController which is set up with multiple ViewControllers at launch. When the user clicks a button I want to send them to a different ViewController in the TabBarController, and pass data through a delegate.
I have a protocol and delegate set up. However, when do you set the delegate since all the ViewControllers are in the TabBarController
Is this possible, how can I pass data to another ViewController in the TabBar when the user clicks a button. Any ideas, I'd really like to use a delegate.
- (IBAction)sendData:(id)sender
{
[self.delegate setStringData:strData];
self.tabBarController.selectedIndex = 0;
}
Edit:
So let's say I have a TabBarController with two ViewControllers called ViewControllerOne and ViewControllerTwo.
I have ViewControllerTwo set up as the delegate and protocol. This is the ViewController that will send data to ViewControllerOne after the button is pressed. ViewControllerOne implements protocol and contains the method setStringData which should be called after the button in ViewControllerTwo is pressed.
From a UIViewController you want to change the selected tab bar index and pass data.
I suggest you add a function in you app delegate for this.
That way your UIViewController won't be tied with a UITabBar (if tomorrow you want to use a different UI idiom, you will just have to change the implementation of your function in your app delegate).
To pass data, i you could try to introspection in your function : you take the current UIViewController of the new selected tab index, verify it responds to your selector and call the function.
Edit :
Let's assume your 'just' have to change the selected tabBar index (e.g. your UIViewController will always be the same on the new tab bar index).
In your first View Controller :
- (IBAction)sendData:(id)sender
{
UIApplicationDelegate * appDelegate = [[UIApplication sharedApplication] delegate];
if ([appDelegate respondToSelector:#selector(goToFirstTabBarWithData:)])
{
[appDelegate performSelector:#selector(goToFirstTabBarWithData:) withObject: strData];
}
}
In your Appdelegate :
- (void)goToFirstTabBarWithData:(NSString *)data
{
self.tabBarController.selectedIndex = 0;
UIViewController * vc = [self.tabBarController.viewControllers objectAtIndex:0];
if ([vc respondToSelector:#selector(setStringData:)])
{
[vc performSelector:#selector(setStringData:) withObject:data];
}
}
In your second View controller (the one you will arrive on) :
- (void)setStringData:(NSString *)data
{
// Do something...
}
I found a simpler solution to my problem. Inside of ViewControllerTwo, I just create an instance of ViewControllerOne and pass it that data I need. Then I change the tabBarController index to ViewControllerOne.
For example:
// A method inside of ViewControllerTwo
ViewController *viewcontrollerOne = [ViewcontrollerOne alloc] init];
[viewcontrollerOne setStringData:str];
[viewcontrollerOne release];
self.tabBarController.selectedIndex = 0;
I have a view that is UIViewController (root) that handles ads and a UINavigationController. In that UINavigationController I have typical layers of controllers. In my custom settings table view controller, I have a button to contact me for support. When the user clicks this button I create a MFMailComposeViewController and would like to present it. I can't present it from the settings table view as it will be underneath my ads, so I need to reference the root view and present it from there. I've tried self.parentViewController.parentViewController where self is the settings table view, but that doesn't work. How should I reference this. It seems like a bad design to have to reference the root view directly and pass it to the settings view.
Get the current keyWindow:
UIWindow *window = [UIApplication sharedApplication].keyWindow;
Get its rootViewController:
UIViewController *rootViewController = window.rootViewController;
NOTE: If an UIAlertView is currently being shown, a new window is being created and assigned to be the keyWindow. There might be other exceptional cases as well that will not keep your application window to be the keyWindow.
In my experience, this is the ideal solution to get the rootViewController:
[[[[UIApplication sharedApplication] delegate] window] rootViewController]
Note: In-case of an active UIAlert or UIActionSheet, you get the Alert or Action Sheet as your key window.
Use the app singleton. Something like:
[[[UIApplication sharedApplication] delegate] rootViewController] should get it if your viewController that is the root is named rootViewController
You can always solve this with 1 line of code but I recommend this Swift way to do it, you can call this from anywhere, its also crash and bug safe:
/// EZSwiftExtensions - Gives you the VC on top so you can easily push your popups
var topMostVC: UIViewController? {
var presentedVC = UIApplication.sharedApplication().keyWindow?.rootViewController
while let pVC = presentedVC?.presentedViewController {
presentedVC = pVC
}
if presentedVC == nil {
print("EZSwiftExtensions Error: You don't have any views set. You may be calling them in viewDidLoad. Try viewDidAppear instead.")
}
return presentedVC
}
Its included as a standard function in:
https://github.com/goktugyil/EZSwiftExtensions
Get the UIApplication object.
Cycle through the windows array to find the keyWindow.
And then get the rootViewController property.
I'm writing a "blackbox" library. In this library I need to add a subView to any app which uses my library.
Therefore, I don't have any reference to the appDelegate nor to the UIWindow of the application.
The only thing the external app is doing now is the following :
myRec = [[Rec alloc] init];
myRec.delegate = self;
[myRec start];
where Rec is the blackbox library and myRec is the instance that's used by an external app.
Of course, I can't get any reference to the view of the app through the delegate member cause it's not defined like the specific type of the external app.
Any ideas on how to get a grasp on the UIWindow object / appDelegate object without knowing their identity in advance ?? Thanks !!
Getting the App Delegate:
id<UIApplicationDelegate> appDelegate = [[UIApplication sharedApplication] delegate];
Getting the UIWindow object:
UIWindow* window = [[UIApplication sharedApplication] keyWindow];
[[UIApplication sharedApplication] delegate]
Will always returns something conform to id<UIApplicationDelegate>
Btw, this is the proper way of doing it, create a protocol that some class in your application is supposed to conform to (i.e. the appDelegate) and pass that class to your library. You library can check that the class is well conform to the protocol and fail with a message in the log if not.
#phix23 his answer in Swift 3:
if let appDelegate = UIApplication.shared.delegate, let window = appDelegate.window {
let yourview = window?.rootViewController?.view
}