1

次のような状況があります: を拡張していUITextView control (MyTextView : UITextView)ます。ランタイム デバイスのバージョンに応じて、さまざまな実装があります。MyTextViewそのため、現在、クラスの実装には多くの「if-else」ステートメントがあります。

より保守しやすくするために、別のクラスに分割したいと思います。

MyTextViewIos5 : MyTextViewMyTextViewIos6:MyTextView

デバイスの iOS バージョンに応じて、どのサブクラスを作成するかを実行時に認識するファクトリ関数を作成します

MyTextView をパラメーターとして使用している場合、このソリューションは完全に機能します。

MyTextView* textView = [Factory createWithFrame:frame];

問題は、MyTextView (externalTextView:MyTextView)特定のメソッドを継承して拡張するクラスがあるときに始まります。そのinitWithFrameメソッドは次のようになります。

- (id)initWithFrame:(CGRect)frame {
    self = [Factory createWithFrame:frame];
    if (self) {
        ...
    }
    return self;
}

スーパーinitwithFrameを呼び出す代わりに、自分の工場を呼び出しています。

特定のメソッドを呼び出すと、 MyTextViewIos5またはMyTextViewIos6が呼び出された特定のメソッドを実装していないexternalTextViewというエラーでアプリがクラッシュします。

それを機能させるための回避策はありますか?

4

2 に答える 2

0

派生元の各クラスは、定義した場合、独自のメソッドでMyTextView呼び出す必要があります。派生クラス インスタンスのカスタム初期化を行う必要がない場合は、単に init メソッドを完全に省略できます。[super initWithFrame]initWithFrame

一般的なケースでは、ファクトリcreateWithFrameは次のようになります。

- (MyTextView*)createWithFrame:(CGRect)frame {

    if (<iOS6>)
         return [[MyTextViewOS6 alloc] initWithFrame];
    if (<iOS5>)
         ...
}

ここで、派生クラスが特別な初期化を必要としない場合はinitWIthFrame、それぞれのクラスでメソッドを省略できます (基本クラスでのみ 1 つを定義します)。

または、次のように工場で初期化を行うこともできます。

- (MyTextView*)createWithFrame:(CGRect)frame {

    if (<iOS6>)
         MyTextViewOS6* view = [[MyTextViewOS6 alloc] initWithFrame];
         view.iOS6SpecificProperty = ...;
         [view iOS6SpecificMethod:...];
         return view;
    if (<iOS5>)
         ...
}

あなたがしていること:

self = [Factory createWithFrame:frame];

の新しいインスタンスを割り当て、元の値MyTextViewを置き換えてselfいます。つまり、次の場合:

externalTextView* view = [[externalTextView alloc] initWithFrame];

まず、タイプ のオブジェクトにメモリが割り当てられますexternalTextView。次に、そのクラスの initWithFrame メソッドが呼び出されます。ここで、initWithFrame 内で行う場合:

self = [Factory createWithFrame:frame];

ファクトリを介して新しいオブジェクトをインスタンス化し、それへのポインタを割り当てていますself(最初は alloc を介して作成されたオブジェクトを指していました)。

お役に立てれば。

于 2013-07-11T19:22:57.027 に答える