说我有这个班级
@interface CustomClass : NSObject
@property (nonatomic, strong) NSArray * nicestArrayEver;
@end
我想创建一个CustomClass的子类,但这里是catch
@interface ASubClassCustomClass : CustomClass
@property (nonatomic, strong) NSMutableArray * nicestArrayEver;
@end
你可以想象的问题是,当我初始化ASubClassCustomClass并调用它的超级初始化器(因为还需要其他属性)时,会创建不可变的nicestArrayEver ..我怎样才能避免它的创建,所以我可以设置可变的?< / p>
注意:这只是一个例子,真正的实现调用了很重要的创建和真正定制的子类(不是NSArray)。
答案 0 :(得分:5)
您可以通过使用不同的支持变量使其工作,在合成它时如下所示:@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
另一种方法可能是在基类中有两个init方法,一个用于实例化属性,一个用于实例化属性,另一个用于子类,这将阻止你创建昂贵的对象扔掉它们。
现在,基类可以直接使用第二个init进行实例化,并进入false状态。您可以通过使用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;
}
答案 1 :(得分:1)
我没有看到你想要这样做的原因,但我建议你这样做:在你的子类中声明一个单独的NSMutableArray属性(让我们称之为nicestMutableArrayEver)并覆盖你的超类NSArray的getter返回mutableArray实例的属性:
- (NSArray *)nicestArrayEver {
return [self nicestMutableArrayEver];
}
这样,只要引用超类属性,就可以恢复mutableArray。
最佳,
答案 2 :(得分:1)
属性应该几乎从不具有可变类型。如果他们这样做,那么调用者可以获得指针并在其背后改变对象的属性。如果一个属性应该是外部可变的,那应该是通过变异方法。
请记住,属性定义接口,而不是实现。 @synthesize
可以从属性声明中创建实现,但如果这样做会出错,则不应该使用它。
因此,第一步是为您的类和子类定义接口,而不考虑实现。只有在知道接口应该是什么之后,才应该设计每个接口的实现。
属性是否是外部可变的,后备实例变量可能需要是可变的。该类可能需要纯粹在内部改变自己的属性。
您可以使基类具有指定的初始化程序,该初始化程序将数组对象作为参数(类型为id
),以便子类的覆盖不必强制转换为将其视为NSMutableArray*
)。然后,类的“普通”初始值设定项将使用NSArray
调用指定的初始值设定项。子类的指定初始值设定项将调用超类的指定初始值设定项,并传入NSMutableArray
以使用。
或者,基类初始值设定项可以调用另一个方法来获取数组。基类实现将返回NSArray
。子类可以覆盖该方法以返回NSMutableArray
。
答案 3 :(得分:-1)
你真的不能这样做。只需使用CustomClass
创建NSMutableArray
即可。您可以将它们创建为id
类型并检查isKindOfClass:
,但这只是一项苦差事而且并非真正必要。
我真的只有两个理由可以看到你要问的事情:
NSMutableArray
CustomClass
修改数组的内容,除非它是ASubClassCustomClass
。虽然这些都是很好的目标,但我会说在这种情况下,简化一下是值得的。