Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Create subclass with different subclass property

Say I have this Class

@interface CustomClass : NSObject

@property (nonatomic, strong) NSArray * nicestArrayEver;

@end

And I want to create a subClass of CustomClass, but here is the catch

@interface ASubClassCustomClass : CustomClass

@property (nonatomic, strong) NSMutableArray * nicestArrayEver;

@end

The issue as you can imagine is that when I initialize ASubClassCustomClass and call it's super initializer (since there is other properties required) the inmutable nicestArrayEver is created.. how can I avoid it's creation so I can set the mutable one?

Note: This is just an example, the real implementation calls a heavy to create and really customized subclass (is not an NSArray).

like image 458
Diego Torres Avatar asked May 26 '12 23:05

Diego Torres


People also ask

Can a subclass have another subclass?

A subclass can be further subclassed. Normally, subclassing specializes or refines a class by adding variables and methods (you cannot remove or hide variables or methods by subclassing).

Can a class have multiple subclass?

A Java class can have only one direct superclass. Java does not support multiple inheritance. Creating a subclass can be as simple as including the extends clause in your class declaration (such as in the declaration in ImaginaryNumber above).

Can an object be a subclass of another class?

Can an object be a subclass of another object? A. Yes—as long as single inheritance is followed.

Can a subclass have its own methods?

Subclass can not access parent private properties (fields) and methods. It can access public , protected and default properties and methods only.


2 Answers

You can make it work, by using different backing variables, when synthesizing it looks like this: @synthesize nicestArrayEver = nicestArrayEverSubClass_;

#import <Foundation/Foundation.h>

@interface CustomClass : NSObject

@property (nonatomic, strong) NSArray * nicestArrayEver;

@end

@implementation CustomClass
@synthesize nicestArrayEver ;

-(id)init
{
    if (self = [super init]) {
        nicestArrayEver = [[NSArray alloc] init];
    }
    return self;
}
@end

@interface ASubClassCustomClass : CustomClass

@property (nonatomic, strong) NSMutableArray * nicestArrayEver;

@end

@implementation ASubClassCustomClass
@synthesize nicestArrayEver = nicestArrayEverSubClass_;

-(id)init{
    if (self = [super init]) {
        nicestArrayEverSubClass_ = [[NSMutableArray alloc] init];
    }
    return self;
}
@end



int main(int argc, const char * argv[])
{

    @autoreleasepool {

        CustomClass *c1 = [[[CustomClass alloc] init] autorelease];
        ASubClassCustomClass *c2 = [[[ASubClassCustomClass alloc] init] autorelease];

        NSLog(@"%@", NSStringFromClass([[c1 nicestArrayEver] class]));
        NSLog(@"%@", NSStringFromClass([[c2 nicestArrayEver] class]));

    }
    return 0;
}

output

2012-05-27 01:59:16.221 NicestArray[2312:403] __NSArrayI
2012-05-27 01:59:16.225 NicestArray[2312:403] __NSArrayM

Another approach could be to have 2 init methods in the base class, one, that will instantiate the property and one, that won't, but leaves that task for the child class — this will prevent you from creating expensive objects just to throw them away.
Now the base class could get instantiated directly with the second init and go to a false state. You can avoid this by checking the self class type with isMemberOfClass:, and throw an error, if the class type is the base class.

@interface CustomClass : NSObject

@property (nonatomic, strong) NSArray * nicestArrayEver;
-(id)initWithoutArray;
@end

@implementation CustomClass
@synthesize nicestArrayEver ;

-(id) initWithoutArray
{
    if (self = [super init]) {
        if ([self isMemberOfClass:[CustomClass class]]) {
            [NSException raise:@"AbstractMethodCall" format:@"%@ should be called only from Subclasses of %@", NSStringFromSelector(_cmd), NSStringFromClass([self class])];
        }
    }
    return self;
}


-(id)init
{
    if (self = [super init]) {
        nicestArrayEver = [[NSArray alloc] init];
    }
    return self;
}
@end

@interface ASubClassCustomClass : CustomClass

@property (nonatomic, strong) NSMutableArray * nicestArrayEver;

@end

@implementation ASubClassCustomClass
@synthesize nicestArrayEver = nicestArrayEverSubClass_;

-(id)init{
    if (self = [super initWithoutArray]) {
        nicestArrayEverSubClass_ = [[NSMutableArray alloc] init];
    }
    return self;
}

@end



int main(int argc, const char * argv[])
{

    @autoreleasepool {

        CustomClass *c1 = [[[CustomClass alloc] init] autorelease];
        ASubClassCustomClass *c2 = [[[ASubClassCustomClass alloc] init] autorelease];

        NSLog(@"%@", NSStringFromClass([[c1 nicestArrayEver] class]));
        NSLog(@"%@", NSStringFromClass([[c2 nicestArrayEver] class]));

        //this works, as it is the subclass
        ASubClassCustomClass *shouldWork = [[[ASubClassCustomClass alloc] init] autorelease];

        // ouch!
        CustomClass *shouldCrash = [[[CustomClass alloc] initWithoutArray] autorelease];

    }
    return 0;
}
like image 95
vikingosegundo Avatar answered Nov 15 '22 17:11

vikingosegundo


I don't see the reason why you would want to do that, but I would advise you to do as follows: in your subclass declare a separate NSMutableArray property (let's call it nicestMutableArrayEver) and override the getter for your superclass NSArray property to return the mutableArray instance:

- (NSArray *)nicestArrayEver {
    return [self nicestMutableArrayEver];
}

This way, you could get back your mutableArray whenever you reference the superclass property.

Best,

like image 32
boliva Avatar answered Nov 15 '22 19:11

boliva