Daisy Sophia Hollman
Daisy Sophia Hollman

Reputation: 6296

Subclassing in Objective-C

I'm a bit new to Objective-C, and I've been trying to do something that apparently isn't allowed, even though it's common practice in other languages (I think).

As a specific example, I want to subclass NSMutableArray to make a SortedMutableArray that always maintains itself in a sorted state. So I subclassed NSMutableArray in the usual manner, adding a NSComparator property that determines the sort order. I overrode the addObject: method to insert objects in a sorted manner:

- (void) addObject:(id)anObject {
    for (int i = 0; i < [self count]; ++i) {
        NSComparisonResult result = (NSComparisonResult)self.comparator([self objectAtIndex:i], anObject); 
        if (result == NSOrderedDescending || result == NSOrderedSame) {
            [super insertObject:anObject atIndex:i];
            break;
        }
        else {
            if (result != NSOrderedAscending) {
                [NSException raise:@"InvalidBlockException" format:@"Block must return one of NSOrderedDescending, NSOrderedAscending, or NSOrderedSame"];
            }
        }
    }
}

and everything compiles great. But when I run the program, I get an error indicating that insertObject:atIndex: is now abstract and needs to be implemented. Reading the documentation, it lists several methods that must be implemented in any subclass of NSMutableArray, one of which is indeed insertObject:atIndex:. But I don't need to change the functionality of insertObject:atIndex:; I want it to word exactly as it does in NSMutableArray. Is there a way that I can do this (in general, too, not just for this specific problem)? Why must certain methods be implemented in subclasses like this? Doesn't that kind of defeat one of the purposes of inheritance, code reuse? I've never seen anything like this in other languages, where a method is concrete in a superclass but becomes abstract when it is subclassed. Does this pattern/concept have a name?

Thanks in advance for any help, and I'm sorry if I'm duplicating another question, but I didn't know what to search for other than "subclass" in the objective-c tag, which gave too many results to find what I was looking for.

Upvotes: 0

Views: 802

Answers (3)

You shouldn't be subclassing NSMutableArray, look up categories. It provides a way to add newer methods to classes

apple's link to categories

Upvotes: 1

Altealice
Altealice

Reputation: 3572

See Dave DeLong's post about why this is a not a good idea.

If you really want to do something like this, you could try, uhmm, "fake-subclassing" it.

in the .h file,

...
NSMutableArray *mutableArray;
...
@property (nonatomic, retain) NSMutableArray *mutableArray;
...
- (void) addObject:(id)anObject;

in the .m file,

...
@synthesize mutableArray;
...
- (void) addObject:(id)anObject {
    [mutableArray addObject:id];
    [mutableArray sortUsingSelector:@selector(yourSortingSelector);
}

- (NSMutableArray)mutableArray {
    return mutableArray;
}
...

Which works and everything. My colleague did a similar class to this before (we were objective-c noobs at the time, about 2-3 weeks into learning how to code).

What I would recommend, however, is to use a Key-Value Observing approach if you can. Try to listen in whenever an element is added, and sort your array when you get the notification. I haven't done this to an NSMutableArray before though, so I don't know how this will work or if it even will.

My 2 cents, hope it helps. Happy holidays! ^_^

Upvotes: 2

Dave DeLong
Dave DeLong

Reputation: 243156

Bad idea. NSArray is actually a class cluster (which is our word for [essentially] an abstract factory). This means that when you alloc/init an NSArray, you don't actually get an NSArray back. You get (usually) an NSCFArray, which is a private subclass.

NSMutableArray is the same deal (it's abstract). When you alloc/init an NSMutableArray, you get an NSCFArray back that has a little internal mutable bit flipped.

The upshot of this is that subclass a class cluster is generally discouraged, because it's a bit more complex than just creating a normal subclass.

What I would recommend is to instead check out the CHDataStructures framework, which has a whole bunch of data structures that do what you're looking for already.

Upvotes: 11

Related Questions