Subclassing with another subclass property

Say I have this class

@interface CustomClass : NSObject @property (nonatomic, strong) NSArray * nicestArrayEver; @end 

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

 @interface ASubClassCustomClass : CustomClass @property (nonatomic, strong) NSMutableArray * nicestArrayEver; @end 

The problem you can imagine is that when I initialize ASubClassCustomClass and call it super-initializer (since there are other necessary properties), inmutable nicestArrayEver is created .. how can I avoid creating it so that I can set mutable?

Note. This is just an example, a real implementation calls for a hard to create and really custom subclass (not NSArray).

+7
source share
4 answers

You can make it work using different supporting variables when the synthesis 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; } 

Exit

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

Another approach may be to have 2 init methods in the base class, one that will create an instance of the property and one that will not, but leaves this task to the child class - this will stop you from creating expensive objects, just drop them.
Now the base class can receive an instance directly with the second init and go into a false state. You can avoid this by checking the class type self with isMemberOfClass: and throwing an error if the class type is a 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; } 
+5
source

I don’t see the reason why you would like to do this, but I would advise you to do the following: declare a separate NSMutableArray property in your subclass (let me call it nicestMutableArrayEver) and override the getter for your superclass NSArray property to return the mutableArray instance:

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

That way, you can return your mutableArray whenever you refer to a property of a superclass.

Best

+1
source

Properties will almost never be of a mutable type. If they do, then the caller can get a pointer and change the properties of the object behind him. If a property needs to be changed externally, it must be through mutation methods.

Remember that properties define an interface, not an implementation. @synthesize can create an implementation from a property declaration, but if that is not right you should not use it.

So, the first step is to define an interface for your class and subclass without regard to implementation. Only after you know what interfaces should be, you should design implementation of each of them.

Regardless of whether the external property is changed, the database instance variable can be volatile. For this class, you may need to completely modify your own property.

You can force the base class to have a designated initializer that takes an array object as a parameter (of type id , so you do not need to override the subclass to handle it as NSMutableArray* ). The initializers of the normal class then called this designated initializer using NSArray . The initializer assigned by the subclass is called by the initializer of the assigned superclass, passing it to NSMutableArray .

Alternatively, the base class initializer could call another method to get the array. The base class implementation will return NSArray . A subclass can override this method to return an NSMutableArray .

+1
source

You cannot do this. Just create a CustomClass using NSMutableArray . You can create them as an id type and check isKindOfClass: but this is just a difficult task and not needed.

In fact, there are only two reasons why I can do what you ask:

  • To avoid the extra overhead of NSMutableArray
  • To prevent CustomClass from changing the contents of an array if it is not an ASubClassCustomClass .

Although these are good goals, I would say that in this case it’s worth simplifying a bit.

-one
source

All Articles