Reference outlet to main NSWindow in AppDelegate (OSX) - objective-c

When you create a new project, I seem to remember you being able to access the basic blank window it creates in the storyboard using self.window in the AppDelegate methods.
I can't seem to set a reference outlet to the AppDelegate.h file via the storyboard either. Am I just hallucinating or is there no way to access the window/controller from AppDelegate?
Am I mixing up iOS and OSX practices?

Using storyboards, it seems impossible to connect the WindowController to AppDelegate. I used the following to get a reference to the main window:
AppDelegate.h
#property (weak) NSWindow* window;
AppDelegate.m
- (void)applicationDidFinishLaunching:(NSNotification *)aNotification {
_window = [[[NSApplication sharedApplication] windows] firstObject];
}
See this question for swift solution. Hope this helps :)

It's working for me.
I added an IBOutlet to my AppDelegate.h
#property (nonatomic) IBOutlet NSWindow *window;
Then in your Interface Builder (MainMenu.xib for me) select App Delegate:
Your IBOutlet should be in the Connection inspector to the right:
Maybe the connection between your .xib and your AppDelegate is lost?

Related

Trouble creating UINavigationController to push just one VC

I'm having trouble on such as trivial but fundamental concept in XCode.
I just want to be able to create an app from scratch and be presented with my root view controller and push and pop some VC for practice.
Believe me, I looked at tons of posts and none of them seem to do the trick.
So my steps were, I created a new xcode project, and created an empty application. I figure hell, lets learn here, instead of creating a single view app.
I went to new file then added a obj-c class and created the XIB with it. I called it RootViewController.
So here's my app delegate h file.
#import <UIKit/UIKit.h>
#import "RootViewController.h"
UINavigationController *navVC;
#interface VCTestAppDelegate : UIResponder <UIApplicationDelegate>
#property (strong, nonatomic) UIWindow *window;
#property (retain, nonatomic) UINavigationController *navVC;
#property (readonly, strong, nonatomic) NSManagedObjectContext *managedObjectContext;
#property (readonly, strong, nonatomic) NSManagedObjectModel *managedObjectModel;
#property (readonly, strong, nonatomic) NSPersistentStoreCoordinator *persistentStoreCoordinator;
- (void)saveContext;
- (NSURL *)applicationDocumentsDirectory;
#end
Notice I'm creating my own UINavigationController called, navVC.
Then here's the beginning and relevant section of my appledelegate m file...
#import "VCTestAppDelegate.h"
#implementation VCTestAppDelegate
#synthesize managedObjectContext = _managedObjectContext;
#synthesize managedObjectModel = _managedObjectModel;
#synthesize persistentStoreCoordinator = _persistentStoreCoordinator;
#synthesize navVC;
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
UIViewController *VC1 = [[UIViewController alloc]initWithNibName:#"RootViewController" bundle:nil];
navVC = [[UINavigationController alloc]initWithRootViewController:VC1];
[[self window] setRootViewController:navVC];
[self.window makeKeyAndVisible];
return YES;
}
And I just created a label on that root VC to verify its showing. Well, nope. No syntax errors and no crashing, the simulator just shows a black screen. What on earth and I doing? Then once I figure this out, I want practice to push and pop view controllers.
I can't believe I can't figure this out. I recently published my own app, but using storyboards. I want to move on to another project now but I want more solid fundamentals without using storyboards. I don't want to limit users of just iOS 5 and higher.
And by the way, I even tried by starting a single view application and adding a VC and when I click my button, it "should"; push the 2nd VC. I know the syntax for that, but when I tested the other app I was messing with, it would go into the IBAction block for the button but it would not push that VC....
I tried [self navigationController] pushview... I even tried just [navVC pushview...] nothing works.
I don't understand what I'm missing and how people made apps manually (programmatically before storyboards).
Any help would be super appreciated. Thanks!
You need to create the window. If you look at the default code for an Empty Application, it will have this line:
self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
If you're creating a simple application for practice, what are you doing with the core data stuff?
The only I can think of is that the UIWindow *window that your app needs is currently nil.
You said you made a XIB: try associating the "window" and "NavigationController" outlets to the correct controllers in the XIB.
Control+click from the controller to the window view. It should give you an option to click on "window". This should associate the window with the controller. Try doing the same with the UINavigationController's controller and view.

Show NSWindow from separate nib (not modal)

How to do it? I simply want to load a window and show it in front of the main window.
NSWindowController* controller = [[NSWindowController alloc] initWithWindowNibName: #"MyWindow"];
NSWindow* myWindow = [controller window];
[myWindow makeKeyAndOrderFront: nil];
This code shows the window for one moment and then hides it. IMHO this is because I don't keep reference to the window (I use ARC). [NSApp runModalForWindow: myWindow]; works perfectly but I don't need to show it modally.
Yes, with ARC if you don't hold a reference to the window it will be torn down as soon you as you exit the routine you were in. You need to hold a strong reference to it in an ivar. [NSApp runModalForWindow: myWindow] is different because the NSApplication object holds a reference to the window as long as it is being run modally.
You should likely do something similar to the following, which creates a strong reference to the NSWindowController instance you create:
.h:
#class MDWindowController;
#interface MDAppDelegate : NSObject <NSApplicationDelegate> {
__weak IBOutlet NSWindow *window;
MDWindowController *windowController;
}
#property (weak) IBOutlet NSWindow *window;
#property (strong) MDWindowController *windowController;
- (IBAction)showSecondWindow:(id)sender;
#end
.m:
#import "MDAppDelegate.h"
#import "MDWindowController.h"
#implementation MDAppDelegate
#synthesize window;
#synthesize windowController;
- (IBAction)showSecondWindow:(id)sender {
if (windowController == nil) windowController =
[[MDWindowController alloc] init];
[windowController showWindow:nil];
}
#end
Note that rather than sending the makeKeyAndOrderFront: method directly to the NSWindowController's NSWindow, you can just use NSWindowController's built-in showWindow: method.
While the above code (and sample project below) use a custom subclass of NSWindowController, you also use a generic NSWindowController and create the instance using initWithWindowNibName: (just make sure the File's Owner of the nib file is set to NSWindowController rather than a custom subclass like MDWindowController).
Sample project:
http://www.markdouma.com/developer/MDWindowController.zip

One App Delegate, Two Windows

I have a simple Cocoa app. It has two windows, each in a separate xib file:
MainMenu.xib
SecondaryWindow.xib
I have an AppDelegate class, which has a reference to the window in MainMenu.xib. I'm trying to make it have a reference to the window in SecondaryWindow.xib. I'm confused about how to do this. I have made an outlet, as such:
#interface AppDelegate : NSObject <NSApplicationDelegate>
#property (assign) IBOutlet NSWindow *window;
#property (assign) IBOutlet NSWindow *secondaryWindow;
#end
Here's the implementation:
#implementation AppDelegate
#synthesize window = _window;
#synthesize secondaryWindow = _secondaryWindow;
- (void)applicationDidFinishLaunching:(NSNotification *)aNotification {
[NSBundle loadNibNamed:#"SecondaryWindow" owner:self];
NSLog(#"_window = %#", _window);
NSLog(#"_secondaryWindow = %#", _secondaryWindow);
}
#end
_secondaryWindow is always (null)
I've add an outlet from in SecondaryWindow.xib connection the second window to the outlet in AppDelegate. What else do I need to do in SecondaryWindow.xib to make the connection complete?
EDIT: added [NSBundle loadNibNamed...]
You need to load it...
By default, MainWindow.xib is loaded by the framework, which creates its own instance of the app delegate.
You should load your second window from your app delegate (try [NSBundle laodNibNamed:#"SecondaryWindow" owner:self]. when you do this, the File's owner will be the application delegate - change the class of the file's owner in interface builder to reflect that and make your connections to it)
Did you set the type of File's Owner in the secondary window's .xib to the type of your app delegate? And did you then connect the window in that .xib to the secondaryWindow outlet of File's Owner?
If you did those things, and if the .xib is properly included in the project and you've specified the name of the file correctly in the +loadNibNamed:owner: message, then your secondaryWindow property should be populated.

Can't link datasource of two tablesView

So I have two TableView in one view of an iOS app. I have connected the delegate of both tableViews to the ViewController, and the app works. The problem is when I connect to the viewController the dataSource, so when I run the app Xcode returns to me a SIGABRT.
Anyonoe knows what am I doing wrong?
Make sure that the tableViews are not pointing to delegates that don't exist anymore. For example you might have deleted a delegate from your code but forgot to delete the connection from the tableview to the delegate.
Can you post your code?
#interface ViewController : UIViewController <UITableViewDelegate, UITableViewDataSource>
{
}
#property (weak, nonatomic) IBOutlet UITableView *Listview;

Mac Development Building Basic Interface

I am going through several example code banks and tutorials and just completely stumbling, a lot of it is due to the fact that these tutorials are written for Xcode < 4.2 and ARC changes a few things.
I am attempting to build an interface with an MVC design pattern. I am using the basic template provided for the Application Delegate. I have added a class called MainWindowController which inherits from NSWindowController. In the Interface Builder, firstly I removed the Window object in the MainMenu nib file (because I want it in a separate file). I create a new Interface called MainWindow(.xib) I change the file owner to MainWindowController I add the Delegate to the Object List. Now at this point something is not clicking.
I do not fully grasp how or what I need to implement in order for the Delegate to essentially load and launch the Window Controller. First I tried linking the outlet for "delegate" in the Window to the actual application delegate (called AppDelegate) and then linking the Window Outlet in the Delegate class to the Window in Interface Builder.
I would like an answer to this but I would be far more happy with the correct documentation describing this process. I'm sure there is something on MacDev but I'm having trouble finding it.
Here's what I'm working with:
#class MainWindow;
#interface AppDelegate : NSObject <NSApplicationDelegate>
#property (strong) MainWindow *mainWindowController;
#property (assign) IBOutlet NSWindow *window;
#property (readonly, strong, nonatomic) NSPersistentStoreCoordinator *persistentStoreCoordinator;
#property (readonly, strong, nonatomic) NSManagedObjectModel *managedObjectModel;
#property (readonly, strong, nonatomic) NSManagedObjectContext *managedObjectContext;
- (IBAction)saveAction:(id)sender;
#end
...
#implementation AppDelegate
#synthesize window;
#synthesize mainWindowController;
#synthesize persistentStoreCoordinator = __persistentStoreCoordinator;
#synthesize managedObjectModel = __managedObjectModel;
#synthesize managedObjectContext = __managedObjectContext;
- (void)applicationDidFinishLaunching:(NSNotification *)aNotification
{
MainWindow *controller = [[MainWindow alloc] initWithWindowNibName:#"MainWindow"];
mainWindowController = controller;
// ... the rest handles the ManagedObject Models...
Solution to date:
#synthesize mainWindowController = _mainWindowController; // IBOutlet is linked in IB
//...
- (void) applicationDidFinishLaunching: (NSNotification *) aNotification
{
//... initialization of event handling etc...
if ( !_mainWindowController ) _mainWindowController = [[ MainWindowController alloc] initWithWindowNibName:#"MainWindow"];
[_mainWindowController showWindow: self];
// ...
The application delegate can manage an NSWindow in the main nib file or it can delegate that task to a controller (NSWindowController) which is typical of document based applications or MVC design patterns. The default nib file specified by the Basic-info.plist defines which nib file is loaded. Typically the default nib should be the main menu, which loads the delegate as well. The delegate should then by means of applicationDidFinishLoading: or awakeFromNib: perform initialization of the controllers and continue appropriate delegation in accordance with the delegation and mvc design patterns.
The main problem I was having was launching the window, which is done by showWindow: . The exacerbation of this problem stemmed from source code from a very old Mac OS X project that used deprecated functions and methods to accomplish delegation and led me down the wrong path. Thanks for the answer, it ultimately had me look in the right place for the right questions and I found the right answer.
Your problem is that in that second xib, "MainWindow", a new AppDelegate object is being created that has absolutely nothing to do with the AppDelegate object in the "MainMenu" xib. The objects in each xib are real objects that get serialized and then loaded at runtime.
This specific issue will be addressed in the Resource Management Guide, "Nib Loading". I can also suggest "Core Application Design".