1
votes

I am creating some sample applications to understand the concepts of view navigation, binding etc in cocoa. Here is the scenario: I have a window that has a tab view(2 tabs) in MainMenu.Xib. I have a text field in the first tab and label in the second tab. I want both of them to reflect the same value and I want to do this using binding. Also, I don't want to use the views provided to me along with the tab view.

These are the steps I have done.

The view of each tab view item is set separately in the applicationDidFinishLaunching: method using the following code:

- (void)applicationDidFinishLaunching:(NSNotification *)aNotification
{
// Insert code here to initialize your application

    //initialize view controllers 
    view1=[[ViewTab1 alloc] initWithNibName:@"ViewTab1" bundle:nil];
    view2=[[ViewTab2 alloc] initWithNibName:@"ViewTab2" bundle:nil];


   //set views
    [[[myTabView tabViewItems] objectAtIndex:0]setView:view1.view];
    [[[myTabView tabViewItems] objectAtIndex:1]setView:view2.view];    


}
  • myTabView is the outlet reference of the tab view from MainMenu.xib in AppDelegate.
  • ViewTab1 is the name of the first view controller (and the xib).
  • ViewTab2 is the name of the second view controller (and the xib).

ViewTab1 has one single text field (and an associated label). I have bound this to a variable(name) declared in AppDelegate. ViewTab2 has a label. I have bound this also to the same variable in AppDelegate.

The variable, 'name' is initialized in the init method of AppDelegate.

AppDelegate.h

....
NSString *name;
....
@property(strong) ViewTab1 *view1;
@property(strong) ViewTab2 *view2;
@property (assign) IBOutlet NSTabView *myTabView;

@property (strong) NSString *name;
....

AppDelegate.m

....
@synthesize myTabView;
@synthesize view1,view2;
@synthesize name;
....
- (id)init {
self = [super init];
if (self) {
    name=@"dummy";
}
return self;
....

Apart from this I haven't done any coding in my program.

In the ViewTab1.xib I got an object and made it an instance of AppDelegate and then connected the delegate reference of the Application object(NSApplication) to the same object. (I hope this is the right way of getting the AppDelegate object.)

I did the same in ViewTab2.xib

Then I bound the text field in ViewTab1 and label in ViewTab2 to this variable in AppDelegate.

When I run the program both the text field and label shows "dummy". But when I change the value in the text field, its not reflected in the label in the second tab( i.e. ViewTab2).

Please tell me what I'm doing wrong.

3
You're doing the bindings in Interface Builder, right? Just double checking.Vervious

3 Answers

2
votes

How to establish binding to the same App delegate object from any loaded Nib?

Yes, I know this frustrated situation as described in question... after many weeks and hundreds pages of documentation for KVO - Notifications - Bindings I think there is one very simple solution for that.

As we can find in some information sources the nib-loading process produce new instances of members... and we need to use binding connection to the old one.

Note that bindings made in InterfaceBuilder are redirect to these new instances automatically after loading nib

Why not redirect the pointer of App delegate to the old instance?

In method where you loads your nib you can test which object is app delegate before and just after nib load. If the new one isn’t the same as the previous one you can redirect it as you want.

This simple example works for me in Xcode3 under 10.5.8 with target to OSX10.5 / i386:

// ***** SOMEWHERE IN DEFAULT APP-DELEGATE.m IMPLEMENTATION

- (IBAction) createOtherWindowFromNib: (id)sender
{
    // ensure that app delegate is set as you want...
    [NSApp setDelegate:self];
    NSLog(@"APP-DELEGAT **** CREATE-TEST-WINDOW ***** WHO IS APP-DELEGATE BEFORE NIB LOAD: %@ ", [[NSApp delegate] description]);


    // we can bind members of the nib to this controller over proxy object named "File’s Owner"
    NSWindowController *otherWinCapo = [[NSWindowController alloc] initWithWindowNibName: @"OtherTestWindow"];

    NSLog(@"APP-DELEGAT **** CREATE-TEST-WINDOW ***** WHO IS APP-DELEGATE AFTER NIB LOAD: %@ ", [[NSApp delegate] description]);

    // make some test for delegates before/after here if you need ...
    // usually your bindings made inside "OtherTestWindow.xib" by IB doesn’t works in this moment

    // ... and some redirection if needed
    [NSApp setDelegate:self];

    // afer that the bind made in IB inside "OtherTestWindow.xib" 
    // referred to (proxy object) "Application.delegate.myBOOL" (Bind to:Application, Model Key Path:delegate.myBOOL)
    // react to changes of myBOOL placed in default app delegate object as expected 
    // simultaneously in every open instance of "OtherTestWindow.xib"

    [otherWinCapo showWindow: otherWinCapo.window]; // we need populate the window instance on screen to see it
}
0
votes

Have you turned on 'Continuously Updates Value' in the NSTextField controls?

See this example.

0
votes

I think the problem is that the objects in your xibs that you set to the app delegate class create 2 different instances of the app delegate, so changing the value of the text field changes the value of name in one instance but not in the other. That's what you're doing wrong, unfortunately, I can't think of a solution at this time.