Simple bindings problem

  • I'm writing some very simple applications to lear how bindings work
    and I've hit upon another problem that I can't figure out. Hopefully
    it's not some dismal typo on my part 8).

    I have a simple application with two NSTextViews - one for displaying
    an integer value and one for displaying an NSString value. My
    AppController has one int member and one NSString member (code below).
    I have an NSObjectController which has it's content bound to my
    AppController. I have bound both of the NSTextViews to my Controller
    and set their Controller Key to 'selection' and their Model Key Path
    to the names of my AppController member variables.

    The problem I am having is that my integer binding is working fine -
    updates from both the model and the view are propigated by the
    binding. But my NSString member is causing a runtime crash:

    2008-01-05 09:45:19.188 BindingsTest[9890:813] *** -[NSTextField
    copyWithZone:]: unrecognized selector sent to instance 0x12bc50
    2008-01-05 09:45:19.189 BindingsTest[9890:813] An uncaught exception
    was raised
    2008-01-05 09:45:19.190 BindingsTest[9890:813] *** -[NSTextField
    copyWithZone:]: unrecognized selector sent to instance 0x12bc50
    2008-01-05 09:45:19.190 BindingsTest[9890:813] *** Terminating app due
    to uncaught exception 'NSInvalidArgumentException', reason: '*** -
    [NSTextField copyWithZone:]: unrecognized selector sent to instance
    0x12bc50'

    Yet both of the bindings are set up the same in IB...

    When I put breakpoints on the setter and getter methods for the
    NSString my code seems to be initialising my AppController fine and
    setting the member variables, but then immediately tries to access a
    different instance for some reason (the 'self' ptr changes). This is
    when the crash happens. Problem is that I have no idea why my code is
    setting up a correct instance of my AppController and then trying to
    read the contents of an invalid instance of my AppController class.
    Can anyone help ? Thank you.

    Here is the code for my AppController:

    ---- header

    #import <Cocoa/Cocoa.h>

    @interface AppController : NSObject {
    int testInt;
    NSString* insertText;
    }

    - (void)setTestInt:(int)intIn;
    - (int)testInt;

    - (NSString*)insertText;
    - (void)setInsertText:(NSString*)insertIn;

    @end

    ---- implimentation

    #import "AppController.h"

    @implementation AppController

    - (id)init
    {
    if( self = [super init] )
    {
      [self setTestInt:10];
      [self setInsertText:@"five"];
    }
    return self;
    }

    - (void)setTestInt:(int)intIn
    {
    NSLog( @"value set to %d", intIn);
    testInt = intIn;
    }

    - (int)testInt
    {
    NSLog(@"testInt read");
    return testInt;
    }

    - (NSString*)insertText
    {
    NSLog(@"reading insertText");
    return insertText;
    }

    - (void)setInsertText:(NSString*)insertIn
    {
    NSLog(@"setting insertText");
    if( insertText != insertIn )
    {
      [insertText release];
      insertText = insertIn;
      [insertText retain];
    }
    }

    @end
  • Sorry, that should read 'with two NSTextFields'.

    On 5 Jan 2008, at 09:58, Martin Linklater wrote:

    > I have a simple application with two NSTextViews - one for
    > displaying an integer value and one for displaying an NSString
    > value. My AppController has one int member and one NSString member
    > (code below). I have an NSObjectController which has it's content
    > bound to my AppController. I have bound both of the NSTextViews to
    > my Controller and set their Controller Key to 'selection' and their
    > Model Key Path to the names of my AppController member variables.
  • OK. My problem was that I had my NSObjectController's Model Key Path
    set to 'selection' rather than 'self'. Doh. I can now bind both
    integers and NSStrings to NSTextFields.

    I now have another question... When you call 'add' on an
    NSArrayController via an action, say by pressing an NSButton on your
    interface, how do you set the actual value of the inserted object ? I
    know you can set the class type of the newly created object with the
    Class Name entry in the array controllers Attributes inspector pane,
    but is there a way to actually setup the contents of the newly created
    array entry ?

    So in my case when I click 'Add' the array controller creates a new
    NSString object in my array, but how do I then set the actual value of
    that NString object ?

    Thanks.
  • On Jan 5, 2008, at 2:02 PM, Martin Linklater wrote:

    > So in my case when I click 'Add' the array controller creates a new
    > NSString object in my array, but how do I then set the actual value
    > of that NString object ?
    >
    Well, how do you do it currently?
    How do you want to do it?
    What opportunities do the controller classes give for customising the
    process?

    mmalc
  • On 6 Jan 2008, at 00:24, mmalc crawford wrote:

    > Well, how do you do it currently?

    Currently in my test app I have an NSPopUpMenu, an NSTextField next to
    it, and two NSButtons (Add and Remove). My NSPopUpMenu is bound to my
    array controller, which has it's contents initialised in my
    AppControllers init method. This inits the NSPopUPMenu with 4 strings.
    I have the Add and Remove buttons triggering the insert: and remove:
    actions of the array controller.

    >
    > How do you want to do it?

    What I would like is for whatever string I enter into the NSTextField
    to be used as the string for the new NSPopUpMenu entry.

    >
    > What opportunities do the controller classes give for customising
    > the process?

    This is the bit I'm investigating. I had hoped there would be a way
    for the NSArrayController's 'insert' action to take a parameter
    setting the contents of the newly created object - kind of a 'use this
    object to initialise the new object' setting in the bindings pane. But
    it seems like this is not possible using IB alone - all you can do is
    insert a new, empty object into the array.

    After googling for a bit last night I found this on CocoaDev:

    There are a number of ways to customize new objects that get added to
    the array:

    Subclass NSArrayController and override newObject or addObject.
    Register as an observer of the array's key in the providing object,
    using KeyValueObserving. You will be informed when a new object is
    added to that array, which you can then modify (the new object will be
    passed to you.)
    In the object providing the content array, implement the
    KeyValueCoding array methods, one of which is
    insertObject:in<Key>AtIndex?:.

    So I'm looking at implementing these suggestions... I just thought
    there may be a way to do it without writing any code... just by
    setting things up in IB.

    Thanks.

    >
    >
    > mmalc
    >
  • On Jan 6, 2008, at 12:22 AM, Martin Linklater wrote:
    > I just thought there may be a way to do it without writing any code
    >
    I'm not sure how many times it's been said now, but to reiterate,
    "Sometimes you have to write some code".

    > After googling for a bit last night I found this on CocoaDev:
    >>
    > There are a number of ways to customize new objects that get added
    > to the array:
    >

    Indeed.
    And which you choose depends on where it makes most sense for your
    particular application.  There may be no Right Answer.

    > Subclass NSArrayController and override newObject or addObject.
    > Register as an observer of the array's key in the providing object,
    > using KeyValueObserving. You will be informed when a new object is
    > added to that array, which you can then modify (the new object will
    > be passed to you.)
    > In the object providing the content array, implement the
    > KeyValueCoding array methods, one of which is
    > insertObject:in<Key>AtIndex?:.
    >
    Or you could use the straightforward "traditional" way.  Connect your
    Add button to the controller you already have in your nib (typically
    your File's Owner in a document-based application, otherwise perhaps
    your App Controller) and put the custom logic in there, just as you
    always would have...
    Your only constraint then is that you add the new object to the array
    in a KVO-compliant manner -- or add it directly to the array controller.

    >> Well, how do you do it currently?
    >
    > Currently in my test app I have an NSPopUpMenu, an NSTextField next
    > to it, and two NSButtons (Add and Remove). My NSPopUpMenu is bound
    > to my array controller, which has it's contents initialised in my
    > AppControllers init method. This inits the NSPopUPMenu with 4
    > strings. I have the Add and Remove buttons triggering the insert:
    > and remove: actions of the array controller.
    >>
    >> How do you want to do it?
    >
    > What I would like is for whatever string I enter into the
    > NSTextField to be used as the string for the new NSPopUpMenu entry.
    >
    Presumably your App Controller could have outlets to the text field
    and the array controller...?
    Or you could subclass NSArrayController to add an outlet to the text
    field...

    mmalc
  • On 6 Jan 2008, at 09:58, mmalc crawford wrote:
    > I'm not sure how many times it's been said now, but to reiterate,
    > "Sometimes you have to write some code".

    Heh - indeed. I'm not averse to writing code 8).. I just thought there
    might be a way to do it just using IB and bindings.

    > Presumably your App Controller could have outlets to the text field
    > and the array controller...?
    > Or you could subclass NSArrayController to add an outlet to the text
    > field...

    Yes - I have subclasses NSArrayCotroller and given it an IBOutlet to
    the NSTextField etc. Works a treat.

    There do seem to be an awful lot of ways to accomplish what you want
    in Obj-C and Cocoa. I've been writing C/C++ for a living 15+ years,
    and the weaker type constraints and generally more flexible
    architecture of Cocoa are taking a little getting used to. Most of the
    external libraries that I use in my day job are very strict in how
    they allow you to accomplish a certain task - Cocoa feels a lot
    different. It *is* falling into place as I try more things, but one of
    my worries is that I pick up too many bad habits and adopt techniques
    that may be frowned upon by more experienced Cocoa programmers.

    Thanks for your patience - it is most appreciated.
previous month january 2008 next month
MTWTFSS
  1 2 3 4 5 6
7 8 9 10 11 12 13
14 15 16 17 18 19 20
21 22 23 24 25 26 27
28 29 30 31      
Go to today