Search code examples
objective-cxcodemacoscocoacocoa-bindings

Xcode OSX, bind NSString to UILabel


I have a Model Class like this:

Header:

@interface RTSecurityModel : NSObject
{
    NSString *code;
}

@property NSString *code;

@end

Implementation:

@implementation RTSecurityModel

@synthesize code;

@end

Then I have my App Delegate:

Header:

@interface RTAppDelegate : NSObject <NSApplicationDelegate>
{
    RTSecurityModel *security;
}

@property (assign) IBOutlet NSWindow *window;

@property RTSecurityModel *security;

@end

Implementation:

@implementation RTAppDelegate

@synthesize security;

- (void)applicationDidFinishLaunching:(NSNotification *)aNotification
{
    security = [[RTSecurityModel alloc] init];
    security.code = @"test";
}

Then in my MainMenu.xib I've create a label and in the Bindings Inspector set "Bind To: App Delegate" with "Model Key Path: security.code".

But nothing is showing when I'm starting my application.

I tried soooo many ways to bind this variable, but no one gave success.

Please help me not to hate XCode and Cocoa!

UPD: http://www.experts-exchange.com/Programming/Languages/C/A_3381-Simple-Binding-Cocoa-GUI-Application-without-Outlets.html

Here is the sample how to set Property and Label value by editing the Text Field

But is there a way to edit Label without editing the Text Field? Or without Text Field at all?

UPD2:

You must not create another instance of Object

security = [[RTSecurityModel alloc] init]; // Kill this

Many many thanks to Viktor Lexington


Solution

  • Instead of using security.code as the model path use code. Use the class RTSecurityModel in the value section of the bindings tab instead of the AppDelegate.

    Here is a demo project.

    Do not bind the Text Field Cell, use the Text Field.

    You can check if a value is null if you fill the Null Placeholder with text, will it show that text instead? Then in time of binding the value it null.

    To see your RTSecurityModel in the Interface Builder you must let it know your class, it won't look for it.

    Add an Object and then set the custom class of it to RTSecurityModel. Then you can choose this object and set the referencing outlet to the property in the App Delegate. Assignment will now be directly reflected in the label.

    enter image description here


    I can think of two ways to solve this programmatically without Interface Builder:

    1. Key Value Coding

      // add an observer for the value on the object that has the method below implemented
      [self addObserver: self forKeyPath: @"security.code" options: NSKeyValueObservingOptionNew context: NULL];
      
      // method will be called when the observer has 'seen' a value change
      -(void) observeValueForKeyPath: (NSString *)keyPath ofObject: (id) object                  change: (NSDictionary *) change context: (void *) context {
          label.text = ...
      }
      
    2. Use a custom setter for code (@synthesize will still create the getter for you)

      - (void)setCode:(NSString *)aString {
          label.text = aString;
      }