4

基本的に、別のクラスの軽量ラッパー クラスとして機能するクラスがあります。その他のクラスを iVar として保持します。iVar の特定のプロパティ (実際にはかなりの数) を公開できるようにしたいのですが、そのためには、次のように各プロパティ アクセサーを書き出す必要があります。

- (void) setProperty:(Class *)value{
    _iVar.property = value;
}
- (Class *) property{
    return  _iVar.property;
}

もちろん、すべてのプロパティに対してこれを行う必要がありますが、これは面倒です (約 30 のプロパティがあります)。これを合成したいのですが、方法がわかりません。

合成は可能ですか?

また、サブクラス化はできません....まあ、できるかもしれませんが、実際にはお勧めしません。iVar クラスは非常に重いです (CoreText を実装しています)。私はむしろ手でメソッドを書きたいと思います。

4

2 に答える 2

4

さて、これが私が見つけた解決策です...何をすべきかがわかれば、非常に簡単になりました。最初に「- (id) forwardingTargetForSelector:(SEL)aSelector」を上書きし、iVar を返します。

- (id) forwardingTargetForSelector:(SEL)aSelector{
    return iVar;
}

ランタイムがメソッドを探しているときに見つからない場合、このメソッドを呼び出して、メッセージを転送する別のオブジェクトがあるかどうかを確認します。通常、このメソッドは nil を返します。ここで nil を返すと、プログラムがクラッシュすることに注意してください (これは適切な動作です)。

問題の 2 番目の部分は、宣言されていないメッセージを送信しようとしたときに表示されるコンパイラ エラー/警告をシャットアウトすることです。これは、実装しないカテゴリを宣言することで簡単に実行できます。

@interface Class (iVarClassMethods)
@propoperty (strong) Class *property1;
......more properties
@end

どこにも実装を入れない限り、別名@implementation Class (category)、コンパイラは文句を言いません(実装がどこかにあると想定します....)。

唯一の欠点は、iVar クラスのインターフェイスのプロパティを変更した場合、上記の方法を使用する他のすべてのクラスを更新する必要があることです。そうしないと、別のクラスが送信しようとしたときにクラッシュします。間違った方法は何ですか (コンパイラは事前に警告しません)。ただし、これは回避できます。カテゴリでプロトコルを宣言できます。代わりに、iVar クラス用に別のプロトコルを作成し、必要なメソッド/プロパティを iVar クラスからプロトコルに移動します。

@protocol iVarClassProtocol
@propoperty (strong) Class *property1;
......more properties
@end

そのプロトコルを iVar サブクラスに追加して、これらのメソッドがプロトコルを通じて宣言されるようにします。

@interface iVarClass <iVarClassProtocol>
....other methods/properties you don't need forwarded
@end

最後に、プロトコルをカテゴリに追加するだけです。したがって、明示的な宣言を持つ前述のカテゴリの代わりに、次のようになります。

@interface Class (iVarClassMethods) <iVarClassProtocol>
@end

ここで、転送するプロパティ/メソッドのいずれかを変更する必要がある場合は、プロトコルでそれらを変更します。間違ったメソッドを転送クラスに送信しようとすると、コンパイラは警告を発します。

于 2012-02-23T19:10:53.410 に答える
2

メッセージをivarに転送できると思います:

- (void) forwardInvocation: (NSInvocation*) invocation
{
    [invocation invokeWithTarget:ivar];
}

- (NSMethodSignature*) methodSignatureForSelector: (SEL) selector
{
    NSMethodSignature *our = [super methodSignatureForSelector:selector];
    NSMethodSignature *ivars = [ivar methodSignatureForSelector:selector];
    return our ? our : ivars;
}

次に、たとえばにキャストして、オブジェクトのタイプを非表示または偽造する必要がありますid。そうしないと、クラスがこれらのメソッドを実装していないとコンパイラが文句を言います。もちろん、そのようなトリックがなくてもうまくいくようなより良いデザインを考え出すことができれば最高です.

于 2012-02-23T15:20:50.793 に答える