Using NSArrayController programmatically in library class

  • Hi
    I am extending a library class which is also one of my application's
    model objects. The Library class contains an NSMutableArray of NSData
    which it absolutely needs to perform its tasks. To extend the class i
    must now also hold metadata about each NSData object in the array
    (i.e. the <item> elements in the array now becomes a pair or triple).

    Conveniently the Hillegass example is similar. In RaisMan the person
    data is displayed in columns of TableView. (and i would like to have a
    tableview maybe also but thats not the point). I should create a new
    object called person.h that defines each element in the array and
    provides the accessor methods for binding to person.expectedRaise and
    person.Name. Then an NSArrayController can give an array for each
    column of the data. Another common method is to make an NSMutableArray
    of NSMutableDictionaries and then binding the dictionary @"key" to the
    arrayController. Either way achieves such a goal.

    But here is the crux of my problem:
    The library object (which encloses these array) must keep its
    interface which is a flat array of NSData (and as originally) is used
    on the api side.

    Can i store internally the complicated array including the metadata
    and use an NSArrayController to expose only the original NSData part
    of each item?

    In other words;
    This would be equivalent to saying that person.Name == persons.person
    and person.expectedRaise is a calculated metadata about the person. If
    i wanted to use an array of persons in a payroll department object
    then i would initialise the department with an array of person names,
    and the payroll department would take care of figuring out what the
    expectedRaise should be for each person. Then the payroll department
    would need to have itself an NSArrayController to map an array of
    string objects taken by the initializer to the internal array of
    person objects.

    Is anything special required to use the NSArrayController
    programmatically as i shall not be using Interface Builder?
  • Can i bind arrayController.contentArray to employees.name ?
    or bind arrayController.contentArray to employees and then bind an
    NSMutableArray to arrayController.arrangedObjects.name ?

    On 6 Sep 2008, at 14:03, dreamcat7 wrote:

    > Hi
    > I am extending a library class which is also one of my application's
    > model objects. The Library class contains an NSMutableArray of
    > NSData which it absolutely needs to perform its tasks. To extend the
    > class i must now also hold metadata about each NSData object in the
    > array (i.e. the <item> elements in the array now becomes a pair or
    > triple).
    >
    > Conveniently the Hillegass example is similar. In RaisMan the person
    > data is displayed in columns of TableView. (and i would like to have
    > a tableview maybe also but thats not the point). I should create a
    > new object called person.h that defines each element in the array
    > and provides the accessor methods for binding to
    > person.expectedRaise and person.Name. Then an NSArrayController can
    > give an array for each column of the data. Another common method is
    > to make an NSMutableArray of NSMutableDictionaries and then binding
    > the dictionary @"key" to the arrayController. Either way achieves
    > such a goal.
    >
    > But here is the crux of my problem:
    > The library object (which encloses these array) must keep its
    > interface which is a flat array of NSData (and as originally) is
    > used on the api side.
    >
    > Can i store internally the complicated array including the metadata
    > and use an NSArrayController to expose only the original NSData part
    > of each item?
    >
    > In other words;
    > This would be equivalent to saying that person.Name ==
    > persons.person and person.expectedRaise is a calculated metadata
    > about the person. If i wanted to use an array of persons in a
    > payroll department object then i would initialise the department
    > with an array of person names, and the payroll department would take
    > care of figuring out what the expectedRaise should be for each
    > person. Then the payroll department would need to have itself an
    > NSArrayController to map an array of string objects taken by the
    > initializer to the internal array of person objects.
    >
    > Is anything special required to use the NSArrayController
    > programmatically as i shall not be using Interface Builder?
    >
    >
    >
    >
  • Hi,
    I have now solved my problem by writing a sample project. Here is the
    solution:

    //
    //  MyDocument.h
    //  Arrays
    //
    //  Created by id on 06/09/2008.
    //  Copyright dreamcat7 2008 . All rights reserved.
    //
    #import <Cocoa/Cocoa.h>

    @interface MyDocument : NSDocument
    {
    NSMutableArray* items;
    NSMutableArray* rep;
    NSArrayController* arrayController;
    }
    @property (retain) NSMutableArray* items;
    @property (retain) NSMutableArray* rep;
    @property (retain) NSArrayController* arrayController;

    @end

    //
    //  MyDocument.m
    //  Arrays
    //
    //  Created by id on 06/09/2008.
    //  Copyright dreamcat7 2008 . All rights reserved.
    //

    #import "MyDocument.h"
    #import "Item.h"
    @implementation MyDocument

    @synthesize items;
    @synthesize rep;
    @synthesize arrayController;

    - (id)init
    {
        self = [super init];

    self.items = [[NSMutableArray alloc] initWithCapacity:6];
    self.rep = [[NSMutableArray alloc] initWithCapacity:6];

    int count = 0;
    while(count < 6)
    {
      Item* newItem = [[Item alloc] initWithString:[NSString
    stringWithFormat:@"Item %i", count]
      integer:(NSUInteger)count number:[NSNumber numberWithInt:count]];

      [items addObject:newItem];
      count++;
    }

    self.arrayController = [[NSArrayController alloc]
    initWithContent:self.items];

    NSLog(@"%@:%s %@", [self class], _cmd,
    arrayController.arrangedObjects);

    NSLog(@"%@:%s Binding to arrayController.string:", [self class], _cmd);

    [self bind:@"rep" toObject:arrayController
    withKeyPath:@"arrangedObjects.string" options:nil];
    NSLog(@"%@:%s %@", [self class], _cmd, rep);
    [self unbind:@"rep"];

    NSLog(@"%@:%s Binding to arrayController.integer:", [self class],
    _cmd);

    [self bind:@"rep" toObject:arrayController
    withKeyPath:@"arrangedObjects.integer" options:nil];
    NSLog(@"%@:%s %@", [self class], _cmd, rep);
    [self unbind:@"rep"];

    NSLog(@"%@:%s Binding to arrayController.number:", [self class], _cmd);

    [self bind:@"rep" toObject:arrayController
    withKeyPath:@"arrangedObjects.number" options:nil];
    NSLog(@"%@:%s %@", [self class], _cmd, rep);
    [self unbind:@"rep"];


        return self;
    }

    //
    //  Item.h
    //  Arrays
    //
    //  Created by id on 06/09/2008.
    //  Copyright 2008 dreamcat7. All rights reserved.
    //

    #import <Cocoa/Cocoa.h>

    @interface Item : NSObject {
    NSString* string;
    NSUInteger integer;
    NSNumber* number;
    }
    @property (copy) NSString* string;
    @property (copy) NSNumber* number;

    - (id)initWithString:(NSString*)aString integer:(NSUInteger)aUint
    number:(NSNumber*)aNumber;

    @end

    //
    //  Item.m
    //  Arrays
    //
    //  Created by id on 06/09/2008.
    //  Copyright 2008 dreamcat7. All rights reserved.
    //

    #import "Item.h"

    @implementation Item
    @synthesize string;
    @synthesize number;

    - (NSUInteger)integer
    {
    return integer;
    }

    - (void)setInteger:(NSUInteger)anInteger
    {
    integer = anInteger;
    }

    - (id)init
    {
    return [self initWithString:nil integer:0 number:nil];
    }

    - (id)initWithString:(NSString*)aString integer:(NSUInteger)aUint
    number:(NSNumber*)aNumber
    {
    self = [super init];
    self.string = aString;
    self.integer = aUint;
    self.number = aNumber;
    return self;
    }

    - (void)dealloc
    {
    [string release];
    [number release];
    [super dealloc];
    }
    @end

    On 6 Sep 2008, at 15:47, dreamcat7 wrote:

    >
    > Can i bind arrayController.contentArray to employees.name ?
    > or bind arrayController.contentArray to employees and then bind an
    > NSMutableArray to arrayController.arrangedObjects.name ?
    >
    > On 6 Sep 2008, at 14:03, dreamcat7 wrote:
    >
    >> Hi
    >> I am extending a library class which is also one of my
    >> application's model objects. The Library class contains an
    >> NSMutableArray of NSData which it absolutely needs to perform its
    >> tasks. To extend the class i must now also hold metadata about each
    >> NSData object in the array (i.e. the <item> elements in the array
    >> now becomes a pair or triple).
    >>
    >> Conveniently the Hillegass example is similar. In RaisMan the
    >> person data is displayed in columns of TableView. (and i would like
    >> to have a tableview maybe also but thats not the point). I should
    >> create a new object called person.h that defines each element in
    >> the array and provides the accessor methods for binding to
    >> person.expectedRaise and person.Name. Then an NSArrayController can
    >> give an array for each column of the data. Another common method is
    >> to make an NSMutableArray of NSMutableDictionaries and then binding
    >> the dictionary @"key" to the arrayController. Either way achieves
    >> such a goal.
    >>
    >> But here is the crux of my problem:
    >> The library object (which encloses these array) must keep its
    >> interface which is a flat array of NSData (and as originally) is
    >> used on the api side.
    >>
    >> Can i store internally the complicated array including the metadata
    >> and use an NSArrayController to expose only the original NSData
    >> part of each item?
    >>
    >> In other words;
    >> This would be equivalent to saying that person.Name ==
    >> persons.person and person.expectedRaise is a calculated metadata
    >> about the person. If i wanted to use an array of persons in a
    >> payroll department object then i would initialise the department
    >> with an array of person names, and the payroll department would
    >> take care of figuring out what the expectedRaise should be for each
    >> person. Then the payroll department would need to have itself an
    >> NSArrayController to map an array of string objects taken by the
    >> initializer to the internal array of person objects.
    >>
    >> Is anything special required to use the NSArrayController
    >> programmatically as i shall not be using Interface Builder?
    >>
    >>
    >>
    >>
    >