In a Cooca Application the MainMenu.xib is setup for you in the standard template. This nib has been setup with the application delegate too. In the info.plist the key "Main nib file bas ename" sets the nib file to load at startup.
I want the application to start if possible without a nib, I want to load the MainMenu.xib at applicationDidFinishLaunching in the application's main delegate.
Is it possible?
First, comment out NSApplicationMain in supporting files -> main.m. NSApplicationMain() loads the main nib mentioned in your Info.plist, so skip it. Instead, setup the app and delegate and run the application:
int main(int argc, const char * argv[])
{
//return NSApplicationMain(argc, argv);
#autoreleasepool {
NSApplication * application = [NSApplication sharedApplication];
MYAppDelegate* appDelegate = [[MYAppDelegate alloc] init];
[application setDelegate:appDelegate];
[application run];
}
return EXIT_SUCCESS;
}
Then, in the app delegate's applicationDidFinishLaunching: function, call something similar to createMainWindow:
- (void)createMainWindow
{
self.wincon = [[MYCustomWindowController alloc] initWithWindowNibName:#"MainMenu"];
self.window = self.wincon.window; // window property in appdelegate created for single-view app
// Also had to connect About: to application's orderFrontStandardAboutPanel
}
MainMenu.xib's File's Owner custom class should be switched to MYCustomWindowController from the application.
If MainMenu.xib has a window like in this example, it's "referencing outlet" needs to be connected to File's Owner->window.
If you started with a single view application, DELETE the App Delegate object from MainMenu.xib -- otherwise the xib will create a second instance of your app delegate. This can be terrible if you're referencing something like MYAppDelegate.managedObjectContext. If you need to bind to the application delegate, you can bind to the Application with a key path of delegate.managedObjectContext.
Why did I do this? Because sometimes my application launches with a GUI, and sometimes it doesn't.
This is possible, but seldom worth the trouble IMO. If you have a bundle already there is little cost in including a small nib file (menu only; no window). If you want to load the rest of your UI from a separate nib file after launch, that's fine. But I recommend allowing MainMenu.nib to load and provide the main menu. (You're not clear on what problem you're trying to solve with your approach.)
That said, Lap Cat wrote a series of articles on this called "Working without a nib" that's worth reading. You'll want the last article The Empire Strikes Back where he includes the link to his nibless project. His technique still works in 10.7.
Related
While sending an app to the app store I received a message stating:
"Invalid info.plist: the info.plist may contain either UIMainStoryboardFile or NSMainNibFile, but must not contain both keys"
After googling around it seems the consensus is to set the "main nib file base name" to "MainWindow" and also to set the "main storyboard file base name" to "MainStoryboard_iPAd". Both options we already have.
The app is designed to run on both iPad and iPhone and the app contains two storyboard files, one for ipad and one for iphone. I cannot find any visible .nib or .xib to manipulate even if I found the correct answer.
Does anyone have any hints on how to work around/fix this so the app will send?
Thanks heaps!
Here is what helped me resolve this issue. Delete the NIB entries.
As the message suggests, you should not have both UIMainStorboardFile and NSMainNibFile set in your Info.plist file. I would suggesy you remove the NSMainNibFile entry.
Since you have two storyboards, one for iPad, and one for iPhone, you can set them as the Main Storyboard separately in the Summary tab of your project:
Unfortunately, #verbumdei's answer did not work for me.
I was trying to turn an iPhone-only project to Universal in iOS 7 and it wasn't working. The iPad's storyboard wasn't being read.
What happened was that Xcode added a key to my .plist that was "Main nib file base name (iPad)". I had to delete that key and add "Main storyboard file base name (iPad)", then set the filename to my storyboard's (i.e. Storyboard-iPad.storyboard).
Check info -> custom IOS target properties
Check Main nib file base name(iPhone/iPad) or Main Storyboard file base name(iPhone/iPad)
If not exist, add them and write your base file name.
It works for me.
For those with problems, I solved without creating a new key, just removed the (iPad) from the existing key
In Main Interface I selected the Storyboard, saved, cleaned the project and voila
As of Xcode 11 go to Info -> Custom iOS Target Properties -> Find Main nib file base name (iPad) and leave value for this key empty. Also, in General -> Deployment Info -> Main interface your value should be empty.
None of the above solutions worked for me.
Therefor what I did was that i added a storyboard property to the AppDelegate and set its value in - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
Below is the code for this:
AppDelegate.h
#property (strong, nonatomic) UIStoryboard* storyboard;
AppDelegate.m
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
if ([UIDevice currentDevice].userInterfaceIdiom == UIUserInterfaceIdiomPad) { // is iPad
self.storyboard = [UIStoryboard storyboardWithName:#"Storyboard_ipad" bundle:Nil];
} else {
self.storyboard = [UIStoryboard storyboardWithName:#"Storyboard_iphone" bundle:Nil];
}
self.window.rootViewController = [self.storyboard instantiateInitialViewController];
[self.window makeKeyAndVisible];
return YES;
}
By default Xcode creates 'Main nib file base name (iPad)' in info.plist file and assign it with name of your iPad storyboard.
Here is resolution
Open Info.plist file-> delete 'Main nib file base name (iPad)' and add another key with name 'Main storyboard file base name (iPad)' and assign it with name of your iPad storyboard file i.e. Main_iPad don't provide extension.
I am having a difficult time implementing this new "feature" of Mac OS X 10.7. For the most part, my application works without my having to do anything. Files reopen on launch as expected. If the file is deleted however, my application opens to nothing and a new, blank document needs to be opened via the File menu.
So, what I have done so far is when a new window is created, I call
[myWindow setRestorationClass:(Class < NSWindowRestoration >)self];
with self being my NSDocument class.
Since restoreWindowWithIdentifier:state:completionHandler: is a class method I can't call my windowController creation method [self makeWindowControllers] from within it nor could I call [self initWithType:error] to create a new document if the one being sent has been deleted. How does one tell if the document being sent has been deleted from within this method?
I've read all I can find on Apple's site and elsewhere on this issue and am getting nowhere. Realize my core understanding of this is lacking and I apologize for that. I appreciate any help. Thank you.
As far as I understand the problem I think you have to enable in your app delegate
- (BOOL)applicationShouldOpenUntitledFile:(NSApplication *)sender;
{
return YES;
}
Did you try that?
I've been attempting to create a Cocoa (desktop) application without using NIBs or XIBs, following the instructions here. All is well, and from Terminal.app I can successfully run the application. However it's spawned without any of the usual decorations, such as a menu bar or a dock icon, behind the terminal window and seemingly attached very much to the terminal process.
I suspected that this might be a consequence of running the binary itself directly from the command line, but playing around a bit I found that at least Calculator.app is more than happy to spawn a "real" application when called using:
$ /Applications/Calculator.app/Contents/MacOS/Calculator
What am I missing, if anything, here? I have also tried loading a XIB file via
NSNib *mainNib = [[NSNib alloc] initWithContentsOfURL:[[NSURL URLWithString:#"../MainMenu.xib"] absoluteURL]];
[NSNib instantiateNibWithOwner:application topLevelObjects:nil];
which seems to find the XIB, but makes no difference (i.e. the GUI isn't fully loaded).
After a bit of fiddling, I found the solution to the issue. Transforming the process type via TransformProcessType and then using the accurately-named [NSApp activateIgnoringOtherApps:YES] did the trick:
ProcessSerialNumber psn = { 0, kCurrentProcess };
OSStatus returnCode = TransformProcessType(& psn, kProcessTransformToForegroundApplication);
[NSApp activateIgnoringOtherApps:YES];
(I also added a custom menu to finish it off). Thanks to Mankarse for the pointers!
You need a NSApplication.. why are you even doing this?
If you create a new GUI application, look at main.m you see that it is spawninng a NSApplication there.
int main(int argc, char *argv[])
{
return NSApplicationMain(argc, (const char **)argv);
}
This requires you to have a bundle btw and if you want to launch a command line utility without the terminal you could either use launchd or create a bundle that you simply double click in the finder.
I am learning Cocoa and my understanding from reading the documentation is that when an application starts the following happens:
A shared application instance is created.
The main nib file is looked up from the applications property list so that the application knows which nib to load.
the run loop is started.
This is fine and makes sense for s single windowed application however I am confused by what xcode does when a document based application is created.
In this case there are two nib files; the first contains the application menu and the second contains the window which represents the NSDocument subclass. when I run the application a new document window is opened automatically.
Based on my understanding of how the application works outlined above I don't understand how my application knows to open the document window once the menu nib has been looked up from the property list. There is no code generated to do this as far as I can see (except for the windowNibName method but where is this called from?)
Can anyone tell me what xcode does differently so that the application knows that it is document based and therefore needs to open a document window?
Update:
What I am trying to understand is how Xcode knows how to do something different if my application is set up as a document based application rather than a single window application. As far as I am aware there is no setting to specify this and Xcode doesn't appear to generate any code to give this different behaviour.
From reading the documents over the last couple of days I think I know how this works but am not sure:
_NSApplication_has a delegate method applicationOpensUntitledFile which is called by the applications delegate.
NSDocumentController is set as the applications delegate by default and the default implementation looks for the presence of the CFBundledTypeInfo to determine if the document is document based or not and responds as is appropriate for the application (I.E. YES for document based application and NO for single window applications).
The majority of the time when a single window application is created the application delegate is replaced by a custom AppController anyway which usually wont contain a definition for the applicationOpenUntitledFile method as it is not appropriate for the type of application.
Hopefully any Cocoa experts can confirm if my understanding is correct or if I am barking up the wrong tree.
When you create a document-based application, you get a few things:
A subclass of NSDocument
A new xib file for this document, in addition to MainMenu.xib
A CFBundleDocumentTypes entry in Info.plist, which tells the app about your NSDocument subclass
When your app opens, the shared NSDocumentController will create a new untitled document using the CFBundleDocumentTypes information.
For more information, read The Document-Based Application Project Template and the rest of the document-based applications guide.
I assume your right. If you create a non based document application, add the document types informations in the -Info.plist and set the delegate of NSApplication in the main.m as following
int main(int argc, const char * argv[])
{
[[NSApplication sharedApplication] setDelegate:[NSDocumentController sharedDocumentController]];
[[NSBundle mainBundle] loadNibNamed:#"MainMenu" owner:NSApp topLevelObjects:nil];
[NSApp run];
}
The behaviour seems to be the same as the the default Document-Based Application template.
No, your assumption is not right, look at the implementation of GNUstep version, in the NSApplication's finishLaunching method:
NSDocumentController *sdc;
sdc = [NSDocumentController sharedDocumentController];
if ([[sdc documentClassNames] count] > 0)
{
didAutoreopen = [sdc _reopenAutosavedDocuments];
}
So it create a instance of NSDocumentController automatically.
I have 2 windows in an xcode project, A and B. A is to capture information, B is to display. I built the windows in IB.
I would like to create a method to control the submit from window A to close window A, and display window B fullscreen.
I am completely new to OBJ C and Cocoa, so Please explain this or provide example code...
If I want to do this, I know I need to create a file from within IB with my A and B to add to my project to add the code, or do I simply add a cocoa file .h and .m to the project. If so, what tells IB that these files correspond to the windows I already created in IB. Once the IBAction is completed I know how to link in IB, but I am at a loss as to how to proceed.
So from what it sounds, you need to declare (in .h):
- (IBAction) closeWindowA:(id)self;
Then tell your application what closeWindowA really does (in. m):
- (IBAction) closeWindowA {
// your code goes here. Look up method(s) for closing the window - don't know them by heart
}
Then, just connect your Button or whatever is triggering the action in Interface builder using the draggable connections. Hope this helps - I also have to recommend 'Cocoa Programming for Mac OSX' by Aaron Hillegas. Helps tremendously in understanding these kinds of things.