1

I can create a stack class quite easily, using push and pop accessor methods to an NSArray, however. I can make this generic to take any NSObject derived class, however, I want to store only a specific class in this stack.

Ideally I want to create something similar to Java's typed lists (List or List) so that I can only store that type in the stack. I can create a different class for each (ProjectStack or ItemStack), but this will lead to a more complicated file structure.

Is there a way to do this to restrict the type of class I can add to a container to a specific, configurable type?

Xetius
  • 44,755
  • 24
  • 88
  • 123
  • possible duplicate of [NSMutableArray - force the array to hold specific object type only](http://stackoverflow.com/questions/5197446/nsmutablearray-force-the-array-to-hold-specific-object-type-only) – Jim Mar 09 '11 at 23:05

3 Answers3

3

NSArray will take any object that implements the same protocol as NSObject; it doesn't need to be derived from NSObject. Because all dispatch in Objective-C is dynamic, inheritance isn't necessary for polymorphism.

Putting that aside, if you've implemented your own push and pop methods, you can easily test the incoming type using isKindOfClass or isMemberOfClass and reject those of the incorrect type.

To go further down, NSMutableArray documents which methods are conceptually primitive below the heading 'Subclassing Notes' in the Overview section at the top of the page. If you subclass NSMutableArray and alter addObject:, replaceObjectAtIndex:withObject: and insertObject:atIndex: to test the type of the incoming object then you can create a typed array.

Tommy
  • 99,986
  • 12
  • 185
  • 204
2

You can try something like this, although I do not recommend it:

@interface TypedMutableStack : NSObject {
   Class type;
@private
   NSMutableArray *internal;
}

- (id) initWithType:(Class) type_;

@end

#define CHECK_TYPE(obj) if(![obj isKindOfClass:type]) {\
      [NSException raise:NSInvalidArgumentException format:@"Incorrect type passed to TypedMutableStack"];\
 }


@implementation TypedMutableStack

- (void) dealloc {
  [internal release];
  [super dealloc];
}

- (id) initWithType:(Class) type_ {
   self = [super init];
   if(self) {
      type = type_;
      internal = [[NSMutableArray alloc] init];
   }
   return self;
}

- (void) addObject:(id) obj {
   CHECK_TYPE(obj);
   [internal addObject:obj];
}

- (void) replaceObjectAtIndex:(NSUInteger) index withObject:(id) obj {
    CHECK_TYPE(obj);
    [internal replaceObjectAtIndex:index withObject:obj];
}

- (void) insertObject:(id) obj atIndex:(NSUInteger) index {
    CHECK_TYPE(obj);
    [internal insertObject:obj atIndex:index];
}

//...
@end
Jacob Relkin
  • 161,348
  • 33
  • 346
  • 320
  • This won't work; `NSMutableArray` and `NSArray` are abstract. You can't subclass them and not provide your own storage mechanism. The easy way to do this is to add an `NSMutableArray` ivar and forward on to that instead of to `super`. – Dave DeLong Mar 09 '11 at 23:59
  • Much better. For consistency, I'd also throw an `NSInvalidArgumentException`, but that's just my style. :) (no need to invent a new exception name that way) – Dave DeLong Mar 10 '11 at 00:15
1

Objective-C doesn't have generics or templates. Hence, idiomatic Objective-C code is written using NSObject * and id everywhere, casting as necessary.

Whatever you want to do, you should model it on the existing frameworks. See how NSArray, NSDictionary, NSSet, etc., are implemented, and follow suit.

Marcelo Cantos
  • 181,030
  • 38
  • 327
  • 365