when you start your app using single view template, and you add the NSLog(#"self.window = %#", self.window); in your first line of the AppDelegate.m's application: didFinishLaunchingWithOptions: method, you can see that self.window exists in your app.
However, when you start your app using empty template, and tried to log the self.window to the console, the result returns null. Even if you add storyboard and a view controller, and set its view controller as the initial view controller, and attempt to log the self.window, the result is the same - its value is set to null.
And note that whichever way you take, you can find you declare #property (strong, nonatomic) UIWindow *window; in AppDelegate.h by default. So I wonder why in the first case, you can see that self.window is initialized and set the value but not in the latter case. Also, if self.window is already declared and initialized in the first case but NOT in the second case, how can I find the initialization code?
It looks like in both cases, the #property declaration is same - and in both cases, as I mentioned, I tried to log the value of self.window in the FIRST LINE of the AppDelegate.m's application: didFinishLaunchingWithOptions: method.
So anything that I'm missing? I don't know why those two cases act differently despite me not finding any differences in both code and storyboard.
I use iOS 7 and Xcode 5. Thanks.
OK, when you create a project with a Storyboard or Nib then the project settings will tell the project that the storyboard/nib is the "Main Interface".
This triggers the application to load that interface on start up. This is why the self.window is created in these cases.
When you create an empty application there is no interface to set as the main interface.
You then need to create the window yourself like this...
-(void)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
UIViewController *someController = [UIViewController... //create your initial controller
[self.window addSubview:navigationController.view];
[self.window makeKeyAndVisible];
}
Something like this anyway. It's been a while.
Alternatively, if you create an empty application and then add a nib file that you want to use as the initial nib then you can select it in the project settings.
In the Target in General. In the section "Deployment Info" select the "Main Interface" from the nibs in your project. This will then load that nib when the application starts.
Xcode declares UIWindow as IBOutlet Object in Appdelegate and xcode itself hooks or connect it with the window of default ViewController.nib(Created by Xcode when you create non empty project).There is no need to initialise any object if you have declared it as Iboutlet and connected it with any UIController in nib.
Now in empty project if you want to create window declare it as outlet and connect it with window in exist in nib and make your AppDelegate as Files OWner.
Related
A snippet of the default code in a Master-Detail Xcode project
AppDelegate.m
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
// Override point for customization after application launch.
UINavigationController *navigationController = (UINavigationController *)self.window.rootViewController; // *** here ***
MasterViewController *controller = (MasterViewController *)navigationController.topViewController;
controller.managedObjectContext = self.managedObjectContext;
return YES;
}
AppDelegate.h
#property (strong, nonatomic) UIWindow *window;
I am aware that #synthesize just sets the accessor methods, and no initialization happens automagically. But how does window have a non-nil rootViewController if it is never explicitly initialized? Is this just Xcode init'ing behind the scenes?
From my book:
If you choose the Storyboard option as you specify a template, the process works a little differently. The app is given a main storyboard, pointed to by the Info.plist key “Main storyboard file base name” (UIMainStoryboardFile). After UIApplicationMain instantiates the app delegate class, it asks the app delegate for the value of its window property; if that value is nil, the window is created and assigned to the app delegate’s window property. The storyboard’s initial view controller is then instantiated and assigned to the window’s rootViewController property, with the result that its view is placed in the window as its root view; the window is then sent the makeKeyAndVisible message. All of that is done behind the scenes by UIApplicationMain, with no visible code whatever. That is why, in a storyboard template, the application:didFinishLaunchingWithOptions: implementation is empty.
From the UIWindow documentation:
Note: When you use storyboards and the Xcode app templates to create an app, a window is created for you.
If you don't use storyboards, the window is explicitly created, though all the standard project templates do this out of the box. You'll see a line similar to this in the app delegate:
self.window = [[[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]] autorelease];
Using storyboards, the window is created behind the scenes when the main storyboard is loaded (see the View Controller Programming Guide for more info).
From Apple's docs (in "Using View Controllers in Your App"):
The Main Storyboard Initializes Your App’s User Interface
The main storyboard is defined in the app’s Information property list file. If a main storyboard is declared in this file, then when your app launches, iOS performs the following steps:
It instantiates a window for you.
It loads the main storyboard and instantiates its initial view controller.
It assigns the new view controller to the window’s rootViewController property and then makes the window visible on the screen.
The above answers only who sets the window variable without answering the main questions: "But how does window have a non-nil rootViewController if it is never explicitly initialized? Is this just Xcode init'ing behind the scenes?" and seem to suggest that there is magic afoot. Not a satisfactory answer for me, and so with a little digging, all becomes clear.
The generated code defines AppDelegate as
#UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {
var window: UIWindow?
...
}
When you search the project, there is no other reference to window, so apparently it should remain nil, but actually is set to the correct value (by the methods outlined above). The "magic" is that AppDelegate conforms to the UIApplicationDelegate which includes an declaration:
optional public var window: UIWindow? { get set }
Part of conforming to the UIApplicationDelegate is the redeclaration of the public variable window. When the underlying Application references the variable window in the protocol, it is actually linked to the variable window in our class. When the calling Application updates that variable window in the protocol, it is actually updating our variable window. So when we need to access the value in our program it is ready and waiting.
This is not Xcode magic, but an integral part of the Swift language. When using protocols we can employ the same techniques in our own Swift programs. This is just the same as our implementations of various functions in our classes which we do all the time: e.g. UIApplicationDelegate defines
optional public func applicationDidEnterBackground(_ application: UIApplication)
so we can write our own implementation which is then "magically" called!
For completeness, note the #UIApplicationMain tag on the class. This defines the entry point for the application and is what makes everything work together. The actual class name is irrelevant, and can be given any name you require, as long as it is of type UIResponder and conforms to the UIApplicationDelegate.
In your Storyboard, there is a little arrow you can drag around:
If you were using xibs/nibs instead, the 'Main Interface' field would be filled out.
In the end, yep, it's iOS/Xcode magic.
I created an Empty Application for the iOS and added a ViewController in which gives the following error while
Application windows are expected to have a root view controller at the end of application launch
None of the other google searches seem to help. Thanks in advance.
If using storyboards, delete everything from didFinishLoading in the AddDelegate (except return yes;). Then in the build settings set default storyboard to your storyboard. Add a view controller to your storyboard, make sure it has the white arrow on the side pointing to it. That should be it.
Creating a view controller subclass and nib is not sufficient. You must actually instantiate your view controller in the app delegate's application:didFinishLaunchingWithOptions: method. You'll probably want to use the initWithNibName:bundle: method to do so, and assign the resulting VC to the rootViewController property of the window created by the app delegate.
All you may need to do if you are using storyboards is add one to the project and configure from there.
Place the following code within application:didFinishLaunchingWithOptions:
self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
I have copied some files from a very small (and working) project to a bigger Xcode project.
In particular I have copied a xib file (with just one UIView subclass element), the UIView subclass, and ViewController.
The smaller project simply draws a color background and draws circles as long as the user touches the screen.
I have adapted the code of the bigger project so that at the beginning it loads the xib file. I have added this to the AppDelegate so that it loads the new xib instead of the old one.
(see edit #1 for more details)
Even if drawRect is called (I've tested adding NSLog) nothing is shown[*]. Moreover if I click on the screen of the simulated iPhone the app crashes.
int retVal = UIApplicationMain(argc, argv, nil, nil);
Program received signal EXC_BAD_ACCESS
I am not sure where the problem lies so please let me what I can post.
I have Xcode 4 and I am working with iOS 5.
Thanks for your help. I hope this question is not too naive.
EDIT #1:
This is my xib with a list of classes. I am trying to edit the source code for a Jabber Client that I have found here inserting my own views.
I cannot post image but this is the link
http://i.stack.imgur.com/gDsNb.png
The class CircleDrawer is handling touches and drawing circles.
The class MTViewController is sending a test message.
The class JabberClientAppDelegate (basically unchanged from the downloaded code), connects to the server and authenticates the user. What I have changed is this method:
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
// Override point for customization after application launch.
self.viewController = [[MTViewController alloc] initWithNibName:#"MTViewController" bundle:nil];
self.window.rootViewController = self.viewController;
[self.window makeKeyAndVisible];
return YES;
/*
self.window.rootViewController = self.viewController;
[self.window makeKeyAndVisible];
return YES;*/
}
EDIT #2:
I am starting from scratch.
I am trying to rebuild the app but I get a crash. I have started another discussion since it is not directly relevant to this problem.
EXC_BAD_ACCESS right after touchesBegan
[*]: if I simulate pressing the home button for an instant I can see the background color (then of course I don't see anything else because the simulator returns to the springboard).
Check your MainWindow.xib.
Add appDelegate object below your window (in xib).
Set your class property for appDelegate object to your own appdelegate class.
Then your window object should be connected to appdelegate object's window property.
Now in codebase create object of your viewController class and add subview to window.
Hope this steps will give you some idea about code.
I guess you must have already followed all these steps.
If I create a new project in Xcode 3 - a "Universal" window based project, I can't seem to instantiate the UISplitViewController outlet I am adding to the iPad's XIB.
Starting with a brand new "window-based" project, I select "Universal" from the drop down (iPhone, iPad, Universal). I then create an IBOutlet property in AppDelegate_iPad.h, synthesize the variable in the .m file and release it in the appropriate dealloc.
I open MainWindow_iPad.xib file and add a UISplitViewController object to it. I then connect the "splitViewController" outlet from AppDelegate_iPad to the UISplitViewController I just dragged onto the XIB.
Unfortunately, when I run this, splitViewController is never instantiated. Consequently, I can't add it to the window's view or set it as the window's root controller. I check this by putting a break point in
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
to view the splitViewController ivar - but unfortunately, it is always 0x0. Is there some special step I am missing? I've compared my code to the split view controller template in Xcode and I can't see any differences.
I had the entire app (it consists of one view) set up and ran from a View in the ViewController object of the MainWindow nib, INSTEAD of actually having the view ran from the actual ViewController nib.
The app runs flawlessly, however I have two warnings. I learned that these warnings are caused by me running everything from the MainWindow nib rather than a ViewController.
Are there any issues with running an app from the MainWindow rather than an actual ViewController? The app is text based and involves constantly updating UILabels. You can find it here if you'd like to take a look at what I'm talking about.
Right now having it set up this way causes no issues... however I am planning on expanding the app. I tried copy and pasting my Scroll View to the actual view controller nib, but when I did I just had a grey screen. Can I leave the app as it is?
But what is there in your MainWindow.xib file? If you just want to have window object, go to your applicationDidFinishLaunching method and create a window object.
- (void)applicationDidFinishLaunching:(UIApplication *)application{
UIWindow *appWindow = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
self.window = appWindow;
[appWindow release];
}
Or you could have select the option Window-Based application while creating a new project.