Need help wrapping my head around bindings

  • Hi all, I'm trying to wrap my head around bindings, and I'm trying to
    do it in an Objective-C 2.0 kind of way.  I'm hoping some kindly (and
    well-informed!) individual can help me out.  Here are my questions:

    1) When I create a class instance, it has instance variables.  The
    Objective-C 2.0 method for accessing these is via the @property
    directive.  Does using @property automatically make an instance KVO
    compliant in addition to KVC compliant?  That is, would the following
    declaration (the the corresponding @synthesize) make 'contents'
    something I can bind to?

    @interface CFKcontroller : NSObject {
        NSMutableArray *contents;
    }
    @property(retain) NSMutableArray *contents;
    @end

    2) Assuming that #1 is correct, how do I bind to it using an array
    controller?  I have tried to a) using an array controller bound to
    CFKcontroller for its content, with 'contents' as its key, and I have
    tried binding an object controller to the object, then bind an array
    controller to the object controller.    Neither way worked for me.
    BTW, I have code, but project/code is too large for the list server,
    and I don't have any place I can upload it to.  If anyone wants it, I
    can email it to them directly off the list; zipped, its about 75 KB.

    My ultimate goal is to figure out how to use the new NSCollectionView
    as it appears to be exactly what I want when it comes to quickly
    beating out GUIs for those quick & dirty little apps that people
    always ask me for.

    Any help would be appreciated,
    Cem Karan

    PS, I'm on the list in digest mode, so I may seem to respond slowly,
    or out of order with what everyone is telling me; if so, I apologize.
  • On Dec 10, 2007, at 6:21 PM, Cem Karan wrote:

    > 1) When I create a class instance, it has instance variables.  The
    > Objective-C 2.0 method for accessing these is via the @property
    > directive.  Does using @property automatically make an instance KVO
    > compliant
    >

    No.  Just as with KVC (<http://developer.apple.com/documentation/Cocoa/Conceptual/ObjectiveC/Articl
    es/chapter_5_section_5.html
    >), KVO and properties are orthogonal technologies.

    Using @property per se does not "automatically make an instance KVO
    compliant": typically it will be KVO-compliant by default, but your
    class may suppress automatic key-value observing and you could specify
    non-KVO-compliant accessors for the property.

    > That is, would the following declaration (the the corresponding
    > @synthesize) make 'contents' something I can bind to?
    > @interface CFKcontroller : NSObject {
    > NSMutableArray *contents;
    > }
    > @property(retain) NSMutableArray *contents;
    > @end
    >
    Given this specification, yes you could bind to 'contents'.
    But to preserve encapsulation you should almost certainly copy rather
    than retain the array, and you should implement your own set accessor
    to create a mutable copy.  For efficiency, you should also implement
    the indexed accessors as shown in <http://developer.apple.com/documentation/Cocoa/Conceptual/KeyValueCoding/Co
    ncepts/AccessorConventions.html#//apple_ref/doc/uid/20002174-178830-BAJEDEF
    B
    >.

    > 2) Assuming that #1 is correct, how do I bind to it using an array
    > controller?
    >

    Just as you would any other array.

    > I have tried to a) using an array controller bound to CFKcontroller
    > for its content, with 'contents' as its key,
    >
    What actual binding did you set -- 'contentArray'?

    mmalc
  • Thanks for writing so soon, any and all help is appreciated.

    On Dec 10, 2007, at 11:59 PM, mmalc crawford wrote:
    > On Dec 10, 2007, at 6:21 PM, Cem Karan wrote:
    >
    >> 1) When I create a class instance, it has instance variables.  The
    >> Objective-C 2.0 method for accessing these is via the @property
    >> directive.  Does using @property automatically make an instance KVO
    >> compliant
    >>
    >
    > No.  Just as with KVC (<http://developer.apple.com/documentation/Cocoa/Conceptual/ObjectiveC/Articl
    es/chapter_5_section_5.html
    > >), KVO and properties are orthogonal technologies.
    >
    > Using @property per se does not "automatically make an instance KVO
    > compliant": typically it will be KVO-compliant by default, but your
    > class may suppress automatic key-value observing and you could
    > specify non-KVO-compliant accessors for the property.

    Hmmm... interesting, and it makes sense considering KVO/KVC is not a
    part of the language itself...

    >> That is, would the following declaration (the the corresponding
    >> @synthesize) make 'contents' something I can bind to?
    >> @interface CFKcontroller : NSObject {
    >> NSMutableArray *contents;
    >> }
    >> @property(retain) NSMutableArray *contents;
    >> @end
    >>
    > Given this specification, yes you could bind to 'contents'.
    > But to preserve encapsulation you should almost certainly copy
    > rather than retain the array, and you should implement your own set
    > accessor to create a mutable copy.  For efficiency, you should also
    > implement the indexed accessors as shown in <http://developer.apple.com/documentation/Cocoa/Conceptual/KeyValueCoding/Co
    ncepts/AccessorConventions.html#//apple_ref/doc/uid/20002174-178830-BAJEDEF
    B
    > >.

    Is this correct then?

    @interface CFKcontroller : NSObject {
        NSMutableArray *contents;
    }

    - (unsigned int)countOfContents;
    - (NSString *)objectInContentsAtIndex:(unsigned int)index;
    - (void)getContents:(NSString **)strings range:(NSRange)inRange;
    - (void)insertObject:(NSString *)string inContentsAtIndex:(unsigned
    int)index;
    - (void)removeObjectFromContentsAtIndex:(unsigned int)index;

    @end

    @implementation CFKcontroller

    - (id)init
    {
        if ((self = [super init]) != nil)
        {
            contents = [[NSMutableArray alloc] init];
            [contents addObject:@"Dummy String"];
            NSLog(@"Just loaded the array.  Contents are: %@", contents);
        }
        return self;
    }

    - (unsigned int)countOfContents {
        return [contents count];
    }

    - (NSString *)objectInContentsAtIndex:(unsigned int)localIndex {
        return [contents objectAtIndex:localIndex];
    }

    - (void)getContents:(NSString **)strings range:(NSRange)inRange {
        [contents getObjects:strings range:inRange];
        return; // handy place to put a breakpoint
    }

    - (void)insertObject:(NSString *)string inContentsAtIndex:(unsigned
    int)localIndex {
        NSLog(@"Inserting a string at %u.  The string is: %@",
    localIndex, string);
        [contents insertObject:string atIndex:localIndex];
        return; // handy place to put a breakpoint
    }

    - (void)removeObjectFromContentsAtIndex:(unsigned int)localIndex {
        NSLog(@"Removed the string at index %u", localIndex);
        [contents removeObjectAtIndex:localIndex];
        return; // handy place to put a breakpoint
    }

    @end

    >
    >> 2) Assuming that #1 is correct, how do I bind to it using an array
    >> controller?
    >>
    >
    > Just as you would any other array.

    Hmmm.... OK, I'm doing something seriously wrong then...

    >> I have tried to a) using an array controller bound to CFKcontroller
    >> for its content, with 'contents' as its key,
    >>
    > What actual binding did you set -- 'contentArray'?

    I bound it to 'myController', which is an Object that is an instance
    of CFKcontroller.  The model key path is 'self', although I have also
    tried to attributes to include 'contents' in the Object Controller
    block, and in that case I set the model key path to 'contents'.  In
    each case, I have a termination exception; here is a typical one:

    2007-12-11 21:59:23.947 ArrayControllerTest[1760:10b] *** -
    [_NSControllerObjectProxy copyWithZone:]: unrecognized selector sent
    to instance 0x103d170
    2007-12-11 21:59:23.948 ArrayControllerTest[1760:10b] An uncaught
    exception was raised
    2007-12-11 21:59:23.948 ArrayControllerTest[1760:10b] *** -
    [_NSControllerObjectProxy copyWithZone:]: unrecognized selector sent
    to instance 0x103d170
    2007-12-11 21:59:23.949 ArrayControllerTest[1760:10b] *** Terminating
    app due to uncaught exception 'NSInvalidArgumentException', reason:
    '*** -[_NSControllerObjectProxy copyWithZone:]: unrecognized selector
    sent to instance 0x103d170'
    2007-12-11 21:59:23.952 ArrayControllerTest[1760:10b] Stack: <long
    list of numbers>

    I can send you copies of how I did it both ways; the combined projects
    zipped are 108 KB, and most of that is Xcode's data.  I can't send it
    to the list as it gets rejected for being too large, and I don't have
    a convenient place to upload it to.

    Thanks for the help, I appreciate it.

    Thanks,
    Cem Karan
  • On Dec 11, 2007, at 7:07 PM, Cem Karan wrote:

    >> What actual binding did you set -- 'contentArray'?
    >
    > I bound it to 'myController', which is an Object that is an instance
    > of CFKcontroller.  The model key path is 'self', although I have
    > also tried to attributes to include 'contents' in the Object
    > Controller block, and in that case I set the model key path to
    > 'contents'.  In each case, I have a termination exception; here is a
    > typical one:
    >
    It's not clear why you would have 'self' in the key path?

    Compare your bindings with those in the Bookmarks example at <http://homepage.mac.com/mmalc/CocoaExamples/controllers.html>.
    Look at the 'Content Array' binding for the DNDArrayController in
    MyDocument.nib (see also the array accessors implemented in
    MyDocument.m).

    mmalc
previous month december 2007 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