Relation of employees array to person class?


#1

After reading the chapter and all the posts in this forum, I cannot figure out how the employee array knows that it is populated (sic) with persons?

Please clarify,

Thanks!


#2

It doesn’t and doesn’t need to. In Objective-C, an array object is just a (promiscuos) container. You can add to an array any kind of object, including an array.

The contained objects themselves know what the do.

If you don’t like this behaviour, you can implement your own array, for example, one that allows only a certain kind of object to be inserted (this can be done during run time or during compile time).

Here is an example of how it could be done during run time:

// main.m

#import <Foundation/Foundation.h>
#import "MyArray.h"

int main (int argc, const char * argv[])
{
    @autoreleasepool {
                
        MyArray *widgetArray = [[[MyArray alloc] init] autorelease];
        NSLog (@"--->[wigetArray count] = %lu", [widgetArray count]);
        
        // these two will be thrown away
        [widgetArray addMyWidget:[NSArray array]];
        [widgetArray addMyWidget:[NSString string]];
        NSLog (@"--->[wigetArray count] = %lu", [widgetArray count]);
        
        // this will be accepted
        [widgetArray addMyWidget:[[MyWidget alloc] init]];
        NSLog (@"--->[wigetArray count] = %lu", [widgetArray count]);
    }
    return 0;
}
// MyArray.h

#import <Foundation/Foundation.h>

@interface MyWidget: NSObject
@end

@interface MyArray : NSObject

- (NSUInteger)count;
- (void)addMyWidget:(MyWidget *)widget;
- (MyWidget *)myWidgetAtIndex:(NSUInteger)index;

@end
// MyArray.m

#import "MyArray.h"

// Hiding the array object from the user
//
@interface MyArray ()
@property (nonatomic, retain) NSMutableArray *array;
@end

@implementation MyArray

@synthesize array;

- (void)dealloc
{
    self.array = nil;
    [super dealloc];
}

- (id)init
{
    self = [super init];
    if (self)
    {
        self.array = [NSMutableArray array];
    }
    return self;
}

- (NSUInteger)count
{
    return [array count];
}

- (void)addMyWidget:(MyWidget *)widget
{
    // Allow only instances of MyWidget
    if ([widget isMemberOfClass:[MyWidget class]])
        [array addObject:widget];
    else
        NSLog (@"---> %s: rejecting %@", __PRETTY_FUNCTION__, [widget className]);
    
    // Note: it should also be possible to reject incompatible objects at compile type
    // by setting the appropriate compiler flags; then the above check would be redundant.
}

- (MyWidget *)myWidgetAtIndex:(NSUInteger)index
{
    assert (index < [array count]);
    return [array objectAtIndex:index];
}

@end

@implementation MyWidget

// ...

@end

The above example relies on run-time checks to reject objects that are not instances of MyWidget; compile-time checks should also be possible to achieve the same.


#3

Thanks, but that doesn’t really answer the question. I wanted to know where the person objects are initially introduced to the employees array.


#4

In Interface Builder, select the ArrayController in the dock then go to the Attributes Inspector. Under the “Object Controller” section, the Class Name field should read “Person”. This is where we are telling the ArrayController that it will be managing an array made of Person objects. It is my understanding that we give the necessary keys of our Person class for KVC/KVO to take place.

Prior to placing “Person” as the Class Name, the default is NSMutableDictionary. If you leave the Class Name as NSMutableDictionary and provide the relevant Person class keys, the app will still function. It is my understanding that renaming the Class Name field as Person makes the class of objects in the array explicit. This may have to do with key paths and the like but I haven’t looked into that yet. I would guess that the Person class gets wrapped as an NSMutableDictionary out of sight. But that’s just an assumption.

Anyway, the ArrayController is a general class that manages a collection of objects. In our case, it is the employees array of Person objects.


#5

Thanks that makes sense