说我有这个类
@interface CustomClass : NSObject
@property (nonatomic, strong) NSArray * nicestArrayEver;
@end
我想创建CustomClass的子类,但这里是渔获
@interface ASubClassCustomClass : CustomClass
@property (nonatomic, strong) NSMutableArray * nicestArrayEver;
@end
你可以想像的问题是,当我初始化ASubClassCustomClass并调用它的超初始化(因为需要其他属性)创建inmutable nicestArrayEver ..我怎样才能避免它的创作,所以我可以设置可变的?
注意:这只是一个例子,真正的实现调用了沉重的创建和定制真子(不是一个NSArray)。
你可以把它的工作,通过使用不同的后盾变量,当合成它看起来像这样: @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;
}
产量
2012-05-27 01:59:16.221 NicestArray[2312:403] __NSArrayI
2012-05-27 01:59:16.225 NicestArray[2312:403] __NSArrayM
另一种方法可能是在基类,一个2种初始化方法,将实例属性和一个,那不会,但保留对儿童类的任务 - 这将阻止您创建昂贵的对象只是为了把它们远。
现在的基类可以直接与第二初始化实例化和去假状态。 您可以通过检查自类的类型与避免这种isMemberOfClass:
并抛出一个错误,如果类类型的基类。
@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;
}
我不明白为什么你会想这样做,但我会建议你做如下:在子类中声明一个单独的NSMutableArray属性(姑且称之为nicestMutableArrayEver)和覆盖吸你的超NSArray的属性返回在mutableArray实例:
- (NSArray *)nicestArrayEver {
return [self nicestMutableArrayEver];
}
通过这种方式,你可以只要你引用父财产取回您的mutableArray。
最好,
性能几乎从未应该有可变类型。 如果他们这样做,那么调用者可以得到指针和变异及其背后的对象的属性。 如果属性应该是外部可变的,这应该是通过突变方法。
请记住,属性定义接口,而不是实现。 @synthesize
可以创建一个从财产申报执行,但如果会做错误的事情,你不应该使用它。
所以,第一步是定义你的类和子类的接口,而无需执行方面。 只有当你知道这个接口应该是你应该设计每个执行什么。
是否一个属性是从外部可变的,所述背衬的实例变量可能需要是可变的。 类可能需要纯粹的内部变异自有物业。
你可以做的基类有一个指定初始化这需要数组对象作为参数(类型的id
,这样子类的覆盖不必强制转换为把它当作一个NSMutableArray*
)。 然后,在类的“正常”的初始化会调用与指定初始化NSArray
使用。 子类的指定初始化会调用父类的指定初始化,在路过NSMutableArray
使用。
可替换地,基类初始(一个或多个)可以调用出另一种方法,以获得阵列。 基类的实现将返回一个NSArray
。 子类可以覆盖该方法返回一个NSMutableArray
。
你不能真正做到这一点。 只要创建CustomClass
与NSMutableArray
。 你可以创建这些类型id
和检查isKindOfClass:
但是这只是一个苦差事,而不是真的有必要。
其实只有两个原因,我可以看到做什么你问:
- 要避免的额外开销
NSMutableArray
- 为了防止
CustomClass
修改该数组的内容,除非它是一个ASubClassCustomClass
。
虽然这些都是很好的目标,我会说,在这种情况下,它是值得的,简化一点。