8

このクラスがあるとします

@interface CustomClass : NSObject

@property (nonatomic, strong) NSArray * nicestArrayEver;

@end

そして、CustomClass のサブクラスを作成したいのですが、ここにキャッチがあります

@interface ASubClassCustomClass : CustomClass

@property (nonatomic, strong) NSMutableArray * nicestArrayEver;

@end

ご想像のとおり、問題は、ASubClassCustomClass を初期化してスーパー イニシャライザを呼び出すと (他のプロパティが必要なため)、不変の nicestArrayEver が作成されることです。

注: これは単なる例です。実際の実装では、大量の作成と実際にカスタマイズされたサブクラス (NSArray ではありません) が呼び出されます。

4

4 に答える 4

6

次のように合成するときに、さまざまなバッキング変数を使用して機能させることができます。@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

もう 1 つの方法は、基本クラスに 2 つの init メソッドを用意することです。1 つはプロパティをインスタンス化し、もう 1 つはそうではありませんが、そのタスクを子クラスに任せます。これにより、高価なオブジェクトをスローするためだけに作成することを防ぐことができます。あちらへ。
これで、基本クラスが 2 番目の 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;
}
于 2012-05-27T00:00:39.983 に答える
1

プロパティが可変型を持つことはほとんどありません。その場合、呼び出し元はポインターを取得し、オブジェクトのプロパティを背後で変更できます。プロパティを外部から変更可能にする必要がある場合は、変更メソッドを使用する必要があります。

プロパティは、実装ではなくインターフェイスを定義することに注意してください。@synthesizeプロパティ宣言から実装を作成できますが、それが間違ったことをする場合は使用しないでください。

したがって、最初のステップは、実装に関係なく、クラスとサブクラスのインターフェイスを定義することです。インターフェイスがどうあるべきかを理解して初めて、それぞれの実装を設計する必要があります。

プロパティが外部的に変更可能かどうかにかかわらず、バッキング インスタンス変数は変更可能である必要がある場合があります。クラスは、純粋に内部的に独自のプロパティを変更する必要がある場合があります。

基本クラスに、配列オブジェクトをパラメーターとして受け取る指定されたイニシャライザーを持たせることができます (idサブクラスのオーバーライドがそれを として扱うためにキャストする必要がないようにNSMutableArray*)。次に、クラスの「通常の」イニシャライザは、使用する指定されたイニシャライザを呼び出しNSArrayます。サブクラスの指定された初期化子は、スーパークラスの指定された初期化子を呼び出し、使用する を渡しNSMutableArrayます。

または、基底クラスの初期化子が別のメソッドを呼び出して配列を取得することもできます。基本クラスの実装はNSArray. サブクラスはそのメソッドをオーバーライドして、NSMutableArray.

于 2012-05-27T00:45:21.217 に答える
1

なぜそうする必要があるのか​​ わかりませんが、次のようにすることをお勧めします。サブクラスで別の NSMutableArray プロパティを宣言し(nicestMutableArrayEver と呼びましょう)、スーパークラスの NSArray プロパティの getter をオーバーライドして返すようにします。 mutableArray インスタンス:

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

このようにして、スーパークラス プロパティを参照するたびに、mutableArray を取得できます。

一番、

于 2012-05-27T00:32:01.593 に答える
-1

あなたは本当にそれを行うことはできません. で作成CustomClassするだけNSMutableArrayです。タイプidとチェックとしてそれらを作成することもできますisKindOfClass:が、それは雑用であり、実際には必要ありません。

あなたが求めていることをするために私が見ることができる理由は、実際には2つだけです。

  1. 余分なオーバーヘッドを避けるためにNSMutableArray
  2. CustomClass.でない限り、配列の内容を変更できないようにしますASubClassCustomClass

これらは良い目標ですが、この場合は少し単純化する価値があると思います。

于 2012-05-26T23:41:29.247 に答える