How do I reload a bound NSTableView after adding a record?

  •   In the past, using the Connections approach, after I added a record to
    the Data Source of an NSTableView
      I would do a [myTableView reload]; in the addNewRecord method.
    This was possible because in MyDocument I had an instance variable for
    myTableView and the Connection was made in IB.

    But things are different in using Bindings and I'm still on the
    learning curve.
    So far I have bound the add_a_record Button's target to the MyDocument
    a.k.a. Files' Owner (thank you mmalc).
    As I debug, my data source shows that there are now two objects (having
    started off with only one).
    If I Save the document, close it, and then re-open it the second record
    shows up.
    So that part of it seems to be working as hoped for.

    However the tableview is not redrawn to show the second record when I
    add it.
    I searched the archives and googled but didn't find anything relevant (
    using NSTableView binding reload).

    So how does one get the view updated using bindings?

    TIA for your help...

    respect....

    Peter
    _______________________________________________
    cocoa-dev mailing list | <cocoa-dev...>
    Help/Unsubscribe/Archives: http://www.lists.apple.com/mailman/listinfo/cocoa-dev
    Do not post admin requests to the list. They will be ignored.
  • On Aug 24, 2004, at 11:28 AM, Peter.Teeson wrote:

    > So how does one get the view updated using bindings?
    >
    <http://homepage.mac.com/mmalc/CocoaExamples/controllers.html>
    See section "Programmatic modifications to arrays not noticed by table
    view."

    mmalc
    _______________________________________________
    cocoa-dev mailing list | <cocoa-dev...>
    Help/Unsubscribe/Archives: http://www.lists.apple.com/mailman/listinfo/cocoa-dev
    Do not post admin requests to the list. They will be ignored.
  • Best (eaisest) way I found is the following...

    willChangeValueForKey:
    // do you work here
    // add, remove, whatever you want
    didChangeValueForKey:

    just set the key to whatever your using for your table and the table
    will display itself as needed

    - lee

    > On Aug 24, 2004, at 11:28 AM, Peter.Teeson wrote:
    >
    > So how does one get the view updated using bindings?
    _______________________________________________
    cocoa-dev mailing list | <cocoa-dev...>
    Help/Unsubscribe/Archives: http://www.lists.apple.com/mailman/listinfo/cocoa-dev
    Do not post admin requests to the list. They will be ignored.
  • Lee Thank you very much!!
    I changed my code from this

    - (void)addClientAccount {
    [clientList addUserAccountsRecord];
    }
    to this
    - (void)addClientAccount {
    [self willChangeValueForKey:@"clientList"];
    [clientList addUserAccountsRecord];
    [self didChangeValueForKey:@"clientList"];
    }

    Presto changeo it worked. Wow!
    I also re-read the docn on KVO and they show just what you suggested.
    Boy this bindings stuff does take a while to get an understanding. But
    it's pretty neat really (when it works).

    (mmalc thanks for your web note; do you think adding such an example
    would be helpful in that section?
    Although I read what you wrote I didn't understand it without seeing
    sample code.)

    On Aug 24, 2004, at 18:46, Lee Morgan wrote:

    > Best (eaisest) way I found is the following...
    >
    > willChangeValueForKey:
    > // do you work here
    > // add, remove, whatever you want
    > didChangeValueForKey:
    >
    > just set the key to whatever your using for your table and the table
    > will display itself as needed
    >
    > - lee
    >
    >> On Aug 24, 2004, at 11:28 AM, Peter.Teeson wrote:
    >>
    >> So how does one get the view updated using bindings?
    > _______________________________________________
    > cocoa-dev mailing list | <cocoa-dev...>
    > Help/Unsubscribe/Archives:
    > http://www.lists.apple.com/mailman/listinfo/cocoa-dev
    > Do not post admin requests to the list. They will be ignored.
    _______________________________________________
    cocoa-dev mailing list | <cocoa-dev...>
    Help/Unsubscribe/Archives: http://www.lists.apple.com/mailman/listinfo/cocoa-dev
    Do not post admin requests to the list. They will be ignored.
  • Always glad to be of assistance. Besides mmalc helped me solve this
    problem a matter of days ago :-)

    - lee

    On Aug 24, 2004, at 8:43 PM, Peter.Teeson wrote:

    > Presto changeo it worked. Wow!
    > I also re-read the docn on KVO and they show just what you suggested.
    > Boy this bindings stuff does take a while to get an understanding. But
    > it's pretty neat really (when it works).
    _______________________________________________
    cocoa-dev mailing list | <cocoa-dev...>
    Help/Unsubscribe/Archives: http://www.lists.apple.com/mailman/listinfo/cocoa-dev
    Do not post admin requests to the list. They will be ignored.
  • On Aug 24, 2004, at 5:43 PM, Peter.Teeson wrote:
    > I changed my code from this
    > - (void)addClientAccount {
    > [clientList addUserAccountsRecord];
    > }
    > to this
    > - (void)addClientAccount {
    > [self willChangeValueForKey:@"clientList"];
    > [clientList addUserAccountsRecord];
    > [self didChangeValueForKey:@"clientList"];
    > }
    > Presto changeo it worked. Wow!
    > I also re-read the docn on KVO and they show just what you suggested.
    > Boy this bindings stuff does take a while to get an understanding. But
    > it's pretty neat really (when it works).
    >
    > (mmalc thanks for your web note; do you think adding such an example
    > would be helpful in that section?
    > Although I read what you wrote I didn't understand it without seeing
    > sample code.)
    >
    I do have an example of manual notifications, right at the end, but it
    illustrates a slightly different situation...

    I'm not sure that I would recommend the approach you've taken.
    If I understand correctly, you're adding a new record to an object that
    represents a client list, so that object itself has a to-many
    relationship to userAccountsRecords?

    What the notification you're sending says is that your clientList
    reference has changed.  Whilst it'll work, this is inefficient and
    strictly speaking incorrect.  You should probably (modulo my
    understanding of your design) instead implement a method in the
    ClientList class that adds a record itself, either calling a suitable
    indexed accessor (e.g. insertObject:inUserAccountsRecordsAtIndex:) or
    something more like that shown at the end of my page but for a single
    object.

    mmalc
    _______________________________________________
    cocoa-dev mailing list | <cocoa-dev...>
    Help/Unsubscribe/Archives: http://www.lists.apple.com/mailman/listinfo/cocoa-dev
    Do not post admin requests to the list. They will be ignored.
  • BTW, I'm sorry but I used a different method.
    I used the
    willChange:<#(NSKeyValueChange)change#> valuesAtIndexes:<#(NSIndexSet
    *)indexes#> forKey:<#(NSString *)key#>
    didChange:<#(NSKeyValueChange)change#> valuesAtIndexes:<#(NSIndexSet
    *)indexes#> forKey:<#(NSString *)key#>
    I while the other ones that I posted earlier work fine...as mmalc
    pointed out (this time and before to me) they are very inefficient, as
    they force the entire contents to be updated instead of only the ones
    that need updating.
    Even better would be using mmalc's method mentioned, as it conforms
    better to bindings and Cocoa's overall structure.
    But at any rate it works.

    - lee

    On Aug 24, 2004, at 9:17 PM, mmalcolm crawford wrote:

    > On Aug 24, 2004, at 5:43 PM, Peter.Teeson wrote:
    >> I changed my code from this
    >> - (void)addClientAccount {
    >> [clientList addUserAccountsRecord];
    >> }
    >> to this
    >> - (void)addClientAccount {
    >> [self willChangeValueForKey:@"clientList"];
    >> [clientList addUserAccountsRecord];
    >> [self didChangeValueForKey:@"clientList"];
    >> }
    >> Presto changeo it worked. Wow!
    >> I also re-read the docn on KVO and they show just what you suggested.
    >> Boy this bindings stuff does take a while to get an understanding. But
    >> it's pretty neat really (when it works).
    >>
    >> (mmalc thanks for your web note; do you think adding such an example
    >> would be helpful in that section?
    >> Although I read what you wrote I didn't understand it without seeing
    >> sample code.)
    >>
    > I do have an example of manual notifications, right at the end, but it
    > illustrates a slightly different situation...
    >
    > I'm not sure that I would recommend the approach you've taken.
    > If I understand correctly, you're adding a new record to an object
    > that represents a client list, so that object itself has a to-many
    > relationship to userAccountsRecords?
    >
    > What the notification you're sending says is that your clientList
    > reference has changed.  Whilst it'll work, this is inefficient and
    > strictly speaking incorrect.  You should probably (modulo my
    > understanding of your design) instead implement a method in the
    > ClientList class that adds a record itself, either calling a suitable
    > indexed accessor (e.g. insertObject:inUserAccountsRecordsAtIndex:) or
    > something more like that shown at the end of my page but for a single
    > object.
    >
    > mmalc
    _______________________________________________
    cocoa-dev mailing list | <cocoa-dev...>
    Help/Unsubscribe/Archives: http://www.lists.apple.com/mailman/listinfo/cocoa-dev
    Do not post admin requests to the list. They will be ignored.
  • Thank you Malcom for your time on this.

    On Aug 24, 2004, at 21:17, mmalcolm crawford wrote:
    > On Aug 24, 2004, at 5:43 PM, Peter.Teeson wrote:
    >> I changed my code from this
    >> - (void)addClientAccount {
    >> [clientList addUserAccountsRecord];
    >> }
    >> to this
    >> - (void)addClientAccount {
    >> [self willChangeValueForKey:@"clientList"];
    >> [clientList addUserAccountsRecord];
    >> [self didChangeValueForKey:@"clientList"];
    >> }
    > I do have an example of manual notifications, right at the end, but it
    > illustrates a slightly different situation...
    Yes I saw that under the batch load. But I am only adding a single
    record.
    > I'm not sure that I would recommend the approach you've taken.
    > If I understand correctly, you're adding a new record to an object
    > that represents a client list, so that object itself has a to-many
    > relationship to userAccountsRecords?
    I don't think it's a to-many but maybe my understand is not correct.
    FWIW here is the interface:
    #import <Cocoa/Cocoa.h>
    #import "UserAccountsData.h"

    @interface ClientList : NSDocument {
    UserAccountsData *clientList;
    }
    // Acceessor methods
    - (UserAccountsData *)clientList;
    - (void)setClientList:(UserAccountsData *)newUserAccountsData;
    // Action methods
    - (void)addClientAccount;
    @end

    and here is part of the interface for UserAccountsData:

    #import <Cocoa/Cocoa.h>
    @interface UserAccountsData : NSObject {
    NSMutableArray *userAccountsRecords; // collection of
    UserAccountRecords
    }

    -(id)initWithCoder:(NSCoder *)coder; // designated initialiser

    // Accessor methods
    - (NSMutableArray *)userAccountsRecords;
    - (void)setUserAccountsRecords:(NSMutableArray *)newUserAccountsRecords;
    // Action methods
    - (void)addUserAccountsRecord;

    @end

    // Following are the constituents of a single UserAccountRecord
    // Forward declarations
    @class UserAccountAddress, UserAccountPhonesEtc;

    @interface UserAccountRecord : NSObject {
    NSString *accountID;
    NSString *listingName;
    NSString *billingName;
    UserAccountAddress *mainAddress;
    UserAccountPhonesEtc *mainPhonesEtc;
    UserAccountAddress *secondaryAddress;
    UserAccountPhonesEtc *secondaryPhonesEtc;
    }
    etc.......

    > What the notification you're sending says is that your clientList
    > reference has changed.
    I was hoping that it was saying that the mutable arrray of
    userAccountsRecords has changed because I added a record. Am I wrong
    here?

    > Whilst it'll work, this is inefficient and strictly speaking incorrect.
    > You should probably (modulo my understanding of your design) instead
    > implement a method in the ClientList class that adds a record itself,
    > either calling a suitable indexed accessor (e.g.
    > insertObject:inUserAccountsRecordsAtIndex:) or something more like
    > that shown at the end of my page but for a single object.

    I expect to be able to re-use the UserAccountsData as a base class
    since it's pretty generic. That's why I made ClientList inherit from
    it.
    There will be some other properties of ClientList that are unique to it
    and I'll add them later once I get the fundamental structure working.
    Later on I might make, for example ContactList, also using
    UserAccountsData as the base class, and it too would have unique
    properties of it's own.

    Does this elucidate the design some more? If so does that change your
    advice given above?
    If not I ask you to explain, if you would be so kind and patient, just
    why it is not efficient, and why it is incorrect?

    TIA and

    respect....

    Peter
    _______________________________________________
    cocoa-dev mailing list | <cocoa-dev...>
    Help/Unsubscribe/Archives: http://www.lists.apple.com/mailman/listinfo/cocoa-dev
    Do not post admin requests to the list. They will be ignored.
  • On Aug 25, 2004, at 1:55 PM, Peter.Teeson wrote:

    > Thank you Malcom for your time on this.
    >
    > On Aug 24, 2004, at 21:17, mmalcolm crawford wrote:
    >> On Aug 24, 2004, at 5:43 PM, Peter.Teeson wrote:
    >>> I changed my code from this
    >>> - (void)addClientAccount {
    >>> [clientList addUserAccountsRecord];
    >>> }
    >>> to this
    >>> - (void)addClientAccount {
    >>> [self willChangeValueForKey:@"clientList"];
    >>> [clientList addUserAccountsRecord];
    >>> [self didChangeValueForKey:@"clientList"];
    >>> }
    >> I do have an example of manual notifications, right at the end, but
    >> it illustrates a slightly different situation...
    > Yes I saw that under the batch load. But I am only adding a single
    > record.
    >
    The same general principle (of calling change methods) applies.

    >> I'm not sure that I would recommend the approach you've taken.
    >> If I understand correctly, you're adding a new record to an object
    >> that represents a client list, so that object itself has a to-many
    >> relationship to userAccountsRecords?
    > I don't think it's a to-many but maybe my understand is not correct.
    >
    If I'm following things through correctly, then I would suggest:

    In UserAccountsData:

    @interface UserAccountsData : NSObject {
    NSMutableArray *userAccountsRecords; // collection of
    UserAccountRecords
    }

    // Accessor methods
    - (NSMutableArray *)userAccountsRecords;
    - (void)setUserAccountsRecords:(NSMutableArray *)newUserAccountsRecords;

    Add suitable indexed accessors (probably also remove the standard
    accessors):
    <http://developer.apple.com/documentation/Cocoa/Conceptual/
    KeyValueCoding/Concepts/AccessorConventions.html
    >

    - (unsigned int)countOfUserAccountsRecords;
    - (id)objectInUserAccountsRecordsAtIndex:(unsigned int)index;
    - (void)insertObject:(id)anObject
    inUserAccountsRecordsAtIndex:(unsigned int)index;
    - (void)removeObjectFromUserAccountsRecordsAtIndex:(unsigned int)index;
    // - (void)replaceObjectInUserAccountsRecordsAtIndex:withObject: (This
    is optional, but provides performance enhancements, and may be required
    if you make any modifications to objects in insertObject: inKeyAtIndex:
    that you want to avoid in a replacement.)

    Reimplement:

    - (void)addClientAccount {
    [self willChangeValueForKey:@"clientList"];
    [clientList addUserAccountsRecord];
    [self didChangeValueForKey:@"clientList"];
    }

    back to:

    - (void)addClientAccount {
    [clientList addUserAccountsRecord];
    }

    Implement addUserAccountsRecord something like:

    - (void)addUserAccountsRecord
    {
    UserAccountRecord *newRecord = [[UserAccountRecord alloc] init];
    // do any other initialisation
    [self insertObject: newRecord
      inUserAccountsRecordsAtIndex:[userAccountsRecords count]];
    [newRecord release];
    }

    Note there are no manual KVO notifications -- these are handled
    automatically by the indexed accessor methods.

    (If the client list is managed by an array controller, there may not
    even be any need for addUserAccountsRecord -- leave it to the array
    controller to add a new record using its add: method.)

    > -(id)initWithCoder:(NSCoder *)coder; // designated initialiser
    >
    An aside: This should almost certainly not be the designated
    initialiser for the class.

    >> What the notification you're sending says is that your clientList
    >> reference has changed.
    > I was hoping that it was saying that the mutable arrray of
    > userAccountsRecords has changed because I added a record. Am I wrong
    > here?
    >
    Yes, you're saying that the whole of the UserAccountsData object
    (called 'clientList') has changed, not that that object's
    userAccountsRecords array has been modified.  This is inefficient as
    more updates will be made than is necessary.

    mmalc
    _______________________________________________
    cocoa-dev mailing list | <cocoa-dev...>
    Help/Unsubscribe/Archives: http://www.lists.apple.com/mailman/listinfo/cocoa-dev
    Do not post admin requests to the list. They will be ignored.
previous month august 2004 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
MindNode
MindNode offered a free license !