Switching back and forth between windows XCode interfaces - xcode

I am having a very difficult time switching between forms in Cocoa interfaces. From my initial form and its delegate, I can hide the initial window then load and display the second window with all properties on it. This is working working... Alas, on attempting to return to the initial window, I hide the second window and the initial does not return...
Here are my .h and .m for initial form and for formTwo...
.h
#import <Cocoa/Cocoa.h>
#class frmTwoDelegate;
#interface AppDelegate : NSObject {
#private
frmTwoDelegate *_frmTwo;
}
#property (assign) IBOutlet NSWindow *window;
- (IBAction)BtnSwitchAction:(id)sender;
#end
.m
#import "AppDelegate.h"
#import "frmTwoDelegate.h"
#implementation AppDelegate
- (void)applicationDidFinishLaunching:(NSNotification *)aNotification
{
...
}
- (IBAction)BtnSwitchAction:(id)sender {
if (!_frmTwo) {
_frmTwo = [[DecriptDelegate alloc] initWithWindowNibName:#"frmTwo"];
[_frmTwo setFrmStart:self];
}
[_frmTwo showWindow:sender];
[_window setIsVisible:NO];
}
#end
Here are .h and .m for frmTwo
.h
#import <Cocoa/Cocoa.h>
#class AppDelegate;
#interface frmTwo : NSWindowController{
#private
AppDelegate *frmStart;
__unsafe_unretained NSTextView *_TxtView;
}
#property (retain) AppDelegate *frmStart;
#property (assign) IBOutlet NSWindow *frmTwo;
#property (unsafe_unretained) IBOutlet NSTextView *TxtView;
- (IBAction)BtnOpenActionPreformed:(id)sender;
- (IBAction)BtnBackActionPreformed:(id)sender;
#end
.m
#import "frmTwo.h"
#import "AppDelegate.h"
#implementation frmTwo
#synthesize frmStart;
- (id)initWithWindow:(NSWindow *)window
{
...
}
- (void)windowDidLoad
{
...
}
- (IBAction)BtnOpenActionPreformed:(id)sender
{
...
}
- (IBAction)BtnBackActionPreformed:(id)sender {
[frmStart ShowWindow];
[_frmTwo setIsVisible:NO];
}
#end

Here's a simpler way to achieve what you are doing. I'm not going to write the .h definitions, just infer what the variables represent from their names.
- (IBAction)BtnSwitchAction:(id)sender {
if (!_formTwo) {
_formTwo = [[DecriptDelegate alloc] initWithWindowNibName:#"frmTwo"];
[_formTwo setFrmStart:self];
}
if(_formOne.isVisible) {
[_window close];
[_formTwo showWindow:sender];
} else if(_formTwo.isVisible) {
[_formTwo close];
[_window showWindow:sender];
}
}
In your nib, make sure both windows have the 'Release when closed' checkbox unchecked so your window is not released when you call close. In your second FormTwo window controller, you should call the BtnSwitchAction from your BtnBackActionPreformed method.
I know there's a number of ways you can connect the window switching code to the back button, but I recommend having all the window switching logic in one method on the AppDelegate rather than manipulating OTHER windows from your BtnBackActionPreformed. That controller and method shouldn't know about the details of the other windows, it should just tell the AppDelegate to do the switch.

Related

What is the proper way to declare a delegate variable?

In MyModel.h, I declared a delegate variable like this:
#property(weak) IBOutlet id <MyProtocol> delegate;
I've also seen a delegate variable declared like this:
#property(weak) IBOutlet NSObject <MyProtocol>* delegate;
I'm wondering which I should use.
Also, Xcode 6.2 indicates I'm doing something wrong because when I connect the delegate outlet in IB, Xcode still shows an empty circle to the left of the declaration instead of a filled in circle. This is what I did:
1) In IB, I dragged on Object out of the Library onto the dock, and I changed its class to: MyModel.
2) In IB, I dragged another Object onto the dock, and I changed its class to: MyController. I declared the MyController class like this:
#interface MyController : NSObject <MyProtocol>
#property(strong) IBOutlet MyModel* model;
#end
3) In IB, I hooked up the delegate outlet for the MyModel Object to the MyController Object.
But in Xcode, it still shows an empty circle to the left of the line:
#property(weak) IBOutlet id <MyProtocol> delegate;
In other words, Xcode is saying the outlet is not connected to anything--yet my app is able to communicate with the controller using the delegate property.
If I delete <MyProtocol> from that line, the circle to the left of the line fills in, i.e. Xcode is saying the outlet is now connected to something. Is that an Xcode bug?
Here are the files for my HelloDelegate app:
MyProtocol.h:
//
// MyProtocol.h
// HelloDelegate
//
#class MyModel; //#import "MyModel.h" doesn't work for some reason
#protocol MyProtocol
-(void)sayHello:(MyModel*)model;
#end
MyModel.h:
//
// MyModel.h
// HelloDelegate
//
#import <Foundation/Foundation.h>
#import "MyController.h"
#interface MyModel : NSObject
#property NSString* name;
-(id)initWithName:(NSString*)name;
-(void)doStuff;
#end
MyModel.m:
//
// MyModel.m
// HelloDelegate
//
#import "MyModel.h"
#interface MyModel()
#property(weak) IBOutlet id <MyProtocol> delegate;
#end
#implementation MyModel
-(void)doStuff {
[[self delegate] sayHello:self];
}
-(id) init {
return [self initWithName:#"world"];
}
//Designated initializer:
-(id) initWithName:(NSString *)name {
if (self = [super init]) {
[self setName:name];
}
return self;
}
#end
MyController.h:
//
// MyController.h
// HelloDelegate
//
#import <Foundation/Foundation.h>
#import "MyProtocol.h"
#interface MyController : NSObject <MyProtocol>
#property(strong) IBOutlet MyModel* model;
#end
MyController.m:
//
// MyController.m
// HelloDelegate
//
#import "MyController.h"
#import "MyModel.h"
#import <Cocoa/Cocoa.h>
#interface MyController()
#property(weak) IBOutlet NSTextField* label;
#end
#implementation MyController
-(void)sayHello:(MyModel*)model {
NSString* labelText = [NSString stringWithFormat:#"Hello, %#!", [model name]];
[[self label] setStringValue:labelText];
}
#end
AppDelegate.m:
//
// AppDelegate.m
// HelloDelegate
//
#import "AppDelegate.h"
#import "MyController.h"
#import "MyModel.h"
#interface AppDelegate ()
#property (weak) IBOutlet NSWindow *window;
#property (strong) IBOutlet MyController* controller;
#end
#implementation AppDelegate
- (void)applicationDidFinishLaunching:(NSNotification *)aNotification {
// Insert code here to initialize your application
[[[self controller] model] doStuff];
}
- (void)applicationWillTerminate:(NSNotification *)aNotification {
// Insert code here to tear down your application
}
#end
The main difference comes along when you type something as id <SomeProtocol> and then try to send it a message such as respondsToSelector: and the compiler won't let you. It comes as a surprise - or at least it sure came as a surprise to me - that id <SomeProtocol> is not a form of id. The only messages you can send to such a beast without casting are those defined in the protocol. That's in stark contrast to id plain and simple, which can be sent any known message.
Thus, in my view, as in that of those who know better than I, NSObject <SomeProtocol>* is better, because now this thing is seen by the compiler as an NSObject, and can be sent all the messages declared for NSObject.

Mac OS X Cocoa multiview application navigation

I've already spent 2 full days trying to figure out how to use NSViewControllers in order to create a multiview application.
Here is what I do.
I have 2 View Controllers and the MainMenu.xib's Window.
I also have an AppController that is the delegate for both View Controllers.
When I launch the app, I'm first greeted with the MainMenu.xib's Window's view which holds a button. On clicking this button, an IBAction is sent to the appController and asks for the SecondViewController to display it's nib. So far, everything's fine and the nib file is displayed correctly.
On the secondViewController, there's another button that sends another IBAction to the appController and asks for the FirstViewController to be displayed but nothing happens,
no crash, no warning... Any help would be much appreciated...
Thanks in advance for your patience...
Here is the code for the AppController.h :
#import <Foundation/Foundation.h>
#import "SecondViewController.h"
#import "FirstViewController.h"
#interface AppController : NSObject
#property (strong) IBOutlet NSWindow *mainWindow;
#property (strong) IBOutlet SecondViewController *secondViewController;
#property (strong) IBOutlet FirstViewController *firstViewController;
- (IBAction)secondButtonfromsecondViewControllerClicked:(id)sender;
- (IBAction)buttonClicked:(id)sender;
#end
and here is the code for the AppController.m :
#import "AppController.h"
#implementation AppController
#synthesize mainWindow = mainwindow;
#synthesize secondViewController;
#synthesize firstViewController;
- (IBAction)buttonClicked:(id)sender {
NSLog(#"button from second View Controller clicked");
self.secondViewController = [[SecondViewController
alloc]initWithNibName:#"SecondViewController" bundle:nil];
self.mainWindow.contentView = self.secondViewController.view;
[self.secondViewController.view setAutoresizingMask:NSViewWidthSizable |
NSViewHeightSizable];
}
- (IBAction)secondButtonfromsecondViewControllerClicked:(id)sender {
NSLog(#"button from first ViewController clicked");
self.firstViewController = [[FirstViewController
alloc]initWithNibName:#"FirstViewController" bundle:nil];
self.mainWindow.contentView = [self.firstViewController view];
}
#end
Well, anyone can help me, I just need a single view application that displays a first ViewController with a button on the first viewController that takes me to a second view controller with a second button that takes me back to my first viewcontroller... I've already spent more than a week on that... in vain... PS : I don't want any button on the mainMenu.xib window nor tabs.
here is the solution to my question then.
Here's the code for the AppDelegate.h:
// AppDelegate.h
#import <Cocoa/Cocoa.h>
#import "FirstViewController.h"
#import "SecondViewController.h"
//We need to declare the AppDelegate class as being the delegate for both
//FirstViewController and SecondViewController
#interface AppDelegate : NSObject <NSApplicationDelegate,
FirstViewControllerDelegate, SecondViewControllerDelegate>
#property (strong, nonatomic) NSWindow *window;
#property (strong) FirstViewController *firstViewController;
#property (strong) SecondViewController *secondViewController;
-(void) goToSecondView;
-(void) goToFirstView;
#end
Now, here's the AppDelegate.m:
// AppDelegate.m
#import "AppDelegate.h"
#implementation AppDelegate
#synthesize window = _window;
#synthesize firstViewController;
#synthesize secondViewController;
-(void) awakeFromNib {
[self goToFirstView];
self.firstViewController.delegate = self;
}
-(void) goToSecondView {
if (self.secondViewController ==nil) {
self.secondViewController =[[SecondViewController alloc]
initWithNibName:#"SecondViewController" bundle:nil];
}
self.window.contentView = [self.secondViewController view];
}
-(void) goToFirstView {
if (self.firstViewController ==nil) {
self.firstViewController =[[FirstViewController alloc]
initWithNibName:#"FirstViewController" bundle:nil];
}
self.window.contentView = [self.firstViewController view];
}
#end
Next we need to set delegates in the FirstViewController and the SecondViewController
// FirstViewController.h
#import <Cocoa/Cocoa.h>
#import "SecondViewController.h"
//We declare the delegation protocole:
#protocol FirstViewControllerDelegate <NSObject>
-(void)goToSecondView;
#end
#interface FirstViewController : NSViewController
- (IBAction)firstViewControllerButtonClicked:(id)sender;
#property (nonatomic, strong) id <FirstViewControllerDelegate> delegate;
#end
And here is the FirstViewController.m:
// FirstViewController.m
#import "FirstViewController.h"
#implementation FirstViewController
#synthesize delegate;
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil{
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
self.delegate = [NSApp delegate];
}
return self;
}
- (IBAction)firstViewControllerButtonClicked:(id)sender {
NSLog(#"button from first View Controller clicked");
if ([self.delegate respondsToSelector:#selector(goToSecondView)]) {
[self.delegate goToSecondView];
}
}
#end
Now, same thing for the SecondViewController:
// SecondViewController.h
#import <Cocoa/Cocoa.h>
#protocol SecondViewControllerDelegate <NSObject>
-(void)goToFirstView;
#end
#interface SecondViewController : NSViewController
#property (nonatomic, strong) id <SecondViewControllerDelegate> delegate;
- (IBAction)goToFirstViewControllerButtonClicked:(id)sender;
#end
And here's the SecondViewController.m:
// SecondViewController.m
#import "SecondViewController.h"
#interface SecondViewController ()
#end
#implementation SecondViewController
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil{
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
self.delegate = [NSApp delegate];
}
return self;
}
- (IBAction)goToFirstViewControllerButtonClicked:(id)sender {
NSLog(#"button from Second View Controller clicked");
if ([self.delegate respondsToSelector:#selector(goToFirstView)]) {
[self.delegate goToFirstView];
}
}
#end
Well, I guess this code may be improved and if you have any suggestion, feel free to let me know. Hope it will help others.
THE PROBLEM: When the user presses a button in View2, you want View1 to appear. It's not.
STEP 1: You say that the button should be invoking an action on your AppController. Set a breakpoint (or add a diagnostic log) in that action, just to verify that it is, in fact, being invoked.
STEP 2: Think about what you want that action to do, precisely. My guess is that you want to hide View2 and show View1. Perhaps
[view2 setHidden: YES];
[view1 setHidden: NO];
(I'm not using your names here, of course.) Or you might animate the transitions, either cross-fading the views or moving them.
STEP 3: My guess is that STEP 2 will solve your problem. If it doesn't, use the debugger again to verify that view1 and view2 are not null. (If they're null, you probably have weak variables where you need them to be strong.)
STEP 4: In the unlikely event that you're still stuck, check the frames of view1 and view2. Perhaps view1 isn't where you think it is.
STEP 5: If you're still stuck, check the alphaValue of view1. Maybe you set it to be transparent, and it's being drawn transparently in the right place.
STEP 6: I bet there is no step 6!
This isn't much of an answer at the moment, however I have some concerns about your code that I wanted to work through with you.
Are you sure you have connected the outlets and actions in Interface Builder. Please verify this.
You don't need mainWindow as there is already a window property that points to the main window (verify this in Interface Builder). Also this looks wrong:
#synthesize mainWindow = mainwindow;
^
W
So dump that and just use the existing window outlet provided by Xcode.
Don't re-create the view controllers if they already exist:
if (self.secondViewController == nil)
{
self.secondViewController = [[SecondViewController alloc] initWithNibName:#"SecondViewController"
bundle:nil];
}
self.window.contentView = self.secondViewController.view;

Impossibility to show in a label the text of an object

My objective is to show in a label the text of an object of a custom class called Files. Here is Files.h :
#import <Foundation/Foundation.h>
#interface Files : NSObject
#property (nonatomic, retain) NSString *title;
#property (nonatomic, retain) NSString *text;
#end
This is Files.m :
#import "Files.h"
#implementation Files
#dynamic title;
#dynamic text;
#end
Here is the .h file of my app. the label is called trackName:
#import <UIKit/UIKit.h>
#import "Files.h"
#interface FirstViewController : UIViewController
{
Files *plainpalais;
}
#property (weak, nonatomic) IBOutlet UILabel *trackName;
-(Files*) chooseFile;
#end
This is the .m file of the app:
#import "FirstViewController.h"
#interface FirstViewController ()
#end
#implementation FirstViewController
#synthesize trackName;
-(Files*)chooseFile
{
return plainpalais;
}
- (void)viewDidLoad
{
[super viewDidLoad];
plainpalais.text=#"hello";
plainpalais.title=#"plainpalais";
trackName.text=plainpalais.title;
// Do any additional setup after loading the view, typically from a nib.
}
- (void)viewDidUnload
{
[self setTrackName:nil];
[super viewDidUnload];
// Release any retained subviews of the main view.
}
- (BOOL)shouldAutorotateToInterfaceOrientation: (UIInterfaceOrientation)interfaceOrientation
{
if ([[UIDevice currentDevice] userInterfaceIdiom] == UIUserInterfaceIdiomPhone) {
return (interfaceOrientation != UIInterfaceOrientationPortraitUpsideDown);
} else {
return YES;
}
}
#end
The problem is that the label trackName doesn't show plainpalais...
Thanks for help !
PS: I'm a beginner so this is probably a basic mistake.
You have used #dynamic in your Files.m implementation which tells the compiler that you'll provide getters/setters for these properties at a later time, i.e. using the Objective-C runtime.
I suspect you want to use #synthesize rather than #dynamic. For example,
#import "Files.h"
#implementation Files
#synthesize title;
#synthesize text;
#end
Also you haven't actually created a Files object in the code you have given us. The chooseFile method appears to be returning a nil object (assuming you haven't initialised plainpalais somewhere else). Perhaps you should initialise plainpalais in an init method, e.g.
- (id)init {
self = [super init];
if (self) {
plainpalias = [[Files alloc] init];
}
return self;
}
Don't forget to release this object in dealloc (if you aren't using ARC).

Switching between two NSWindows

I am making a simple mac app in which i want to switch windows.
I have two NSWindowController class MainWindow and DetailWindow
I am using this code :
MainWindow class:
//MainWindow.h
#class DetailWindow;
#interface MainWindow : NSWindowController{
IBOutlet NSButton *btn1;
DetailWindow *detailwindow;
}
#property (nonatomic, retain) IBOutlet NSButton *btn1;
- (IBAction)btn1Event:(id)sender;
//MainWindow.m
#implementation MainWindow
#synthesize btn1;
- (IBAction)btn1Event:(id)sender {
if (!detailwindow) {
detailwindow = [[DetailWindow alloc] initWithWindowNibName:#"DetailWindow"];
}
[detailwindow showWindow:self];
}
#end
DetailWindow Class:
//DetailWindow.h
#class MainWindow;
#interface DetailWindow : NSWindowController{
IBOutlet NSButton *backbtn;
MainWindow *mainwindow;
}
#property (nonatomic, retain) IBOutlet NSButton *backbtn;
- (IBAction)back:(id)sender;
//DetailWindow.m
#implementation DetailWindow
#synthesize backbtn;
- (IBAction)back:(id)sender {
if (!mainwindow) {
mainwindow = [[MainWindow alloc] initWithWindowNibName:#"MainWindow"];
}
[mainwindow showWindow:self];
}
#end
Now the problem is when i click backbtn on DetaiWindow it will open a new MainWindow.
So i have two MainWindow on screen.
I want just main window at front when i click backbtn.
Any help??
Thank you..!!
Your basic problem is that each window is assuming that it is its own job to create the other. Each has an ivar for the other, but there's no external access to it -- via a property or being an IBOutlet or anything else -- so it always starts out as nil, and a new copy gets created instead of reusing the old one.
There are any number of ways to get around this. Probably the easiest would be to create both windows in Interface Builder and link them up there, having made the ivars IBOutlet. Then you know you never have to create them in code at all.
However, purely on the basis of inertia, here's an alternative that sticks closer to what you've got already. Note that I've assumed for simplicity that mainWindow always exists first. If not, you'll have to duplicate the process the other way around.
//MainWindow.h
#class DetailWindow;
#interface MainWindow : NSWindowController
{
IBOutlet NSButton *btn1;
DetailWindow *detailwindow;
}
#property (nonatomic, retain) NSButton *btn1;
- (IBAction)btn1Event:(id)sender;
//MainWindow.m
#implementation MainWindow
#synthesize btn1;
- (IBAction)btn1Event:(id)sender
{
if (!detailwindow)
{
detailwindow = [[DetailWindow alloc] initWithWindowNibName:#"DetailWindow"];
// having created the other window, give it a reference back to this one
detailWindow.mainWindow = self;
}
[detailwindow showWindow:self];
}
#end
//DetailWindow.h
#class MainWindow;
#interface DetailWindow : NSWindowController
{
IBOutlet NSButton *backbtn;
MainWindow *mainwindow;
}
#property (nonatomic, retain) NSButton *backbtn;
// allow the main window to be set from outside
#property (nonatomic, retain) MainWindow *mainWindow;
- (IBAction)back:(id)sender;
//DetailWindow.m
#implementation DetailWindow
#synthesize backbtn;
#synthesize mainWindow;
- (IBAction)back:(id)sender
{
// no window creation on the way back
NSAssert(mainWindow, "mainWindow not set!");
[mainwindow showWindow:self];
}
#end
Untested, so usual caveats apply.
You have to call orderFront: method with self object on main window.
To do this you must find a reference to the main window. A way to do this is:
[NSApp mainWindow];
This call will return you a pointer to your main window (If you did something incorrect, you could have to cycle through the [NSApp windows] array in order to search for your main window).
When you have found the window, send it a orderFront message, by doing (supposing the code above returns the correct window, as explained before).
[[NSApp mainWindow] orderFront:self];
and the window should magically order front.

Checkbox setState:0 on app launch

I'm having a problem with a checkbox. I want to set it to 0 (unchecked) on app launch, but the checkbox is controlled by another class "myClass" for example.
Here's what I did:
I opened Interface Builder and put a checkbox (NSButton) in my window, dragged NSObject in my MainMenu.xib window, renamed it to say "myClass". Added an outlet called "myCheckbox" (NSButton) and linked it to the checkbox I created earlier. Finally, I added some things.
Here's the code for my myClass.m:
#import "myClass.h"
#implementation myClass
- (void) changeState
{
[myCheckbox setState:0];
}
#end
myClass.h
#import <Cocoa/Cocoa.h>
#interface myClass : NSObject {
IBOutlet NSButton *myCheckbox;
}
- (void) changeState;
#end
Then I made some changes in the AppDelegate files so they execute some things when the app is launched:
#import "UntitledAppDelegate.h"
#import "myClass.h"
#implementation UntitledAppDelegate
#synthesize window;
- (void)applicationDidFinishLaunching:(NSNotification *)aNotification {
myClass * someClass = [[myClass alloc] init];
[someClass changeState];
}
#end
UntitledAppDelegate.h:
#import <Cocoa/Cocoa.h>
#interface UntitledAppDelegate : NSObject <NSApplicationDelegate> {
NSWindow *window;
}
#property (assign) IBOutlet NSWindow *window;
#end
The purpose (if this works) is to set a value to the check box depending on the setting stored in the Defaults file.
The problem might be easy or too simple but I'm only a beginner...
Some help would be appreciated, Thanks !
- (void) awakeFromNib
{
[myCheckbox setState:0];
}
in myClass.m solved it.

Resources