2013-06-17 3 views
6

ファクトリメソッドを持つフレームワーククラスから継承したいと思います。ファクトリメソッドが継承したクラス型のオブジェクトを返すようにするにはどうすればよいですか?私は同じような状況を記述するthis useful articleを見つけましたが、その場合はスーパークラスを制御できます。たとえば、のサブクラスで、imageNamed:が私のサブクラス型のオブジェクトを返すと書いてもいいですか?ご例えば目的ファクトリメソッドを持つCクラスの継承

+2

UIImageにカテゴリを書くことで、あなたが望むものを達成できますか? –

+0

はい、私は今この方向について考えています。私はいくつかの追加のクラスメンバー(プロパティ)が必要なだけで、objc_setAssociatedObjectとお友達との混乱を避けたいと思っていました。まったく別の問題のために、このタイプの回避策を作成するのがエレガントではないからです。しかし、私は選択肢がないことをますます心配しています。 – MrTJ

+1

この[NSObject](https://github.com/pixelflut/PixLib-OpenSource/blob/master/PixLib%20OpenSource/NSObject%2BPixLib.m)カテゴリを見てください。 'setRuntimeProperty:name:'と 'runtimeProperty:'の2つのメソッドは、関連オブジェクトの設定とアクセスを容易にします。 –

答えて

9

私はファクトリメソッドを持つフレームワーククラスから継承したいと思います。ファクトリメソッドが継承したクラス型のオブジェクトを返すようにするにはどうすればよいですか?

これはあなたしなければならない必要があるすべてである:

その後
@interface MONImage : UIImage 
@end 

@implementation MONImage 
@end 

私がいることを、たとえば、UIImageのサブクラスを書くことができますどのように
MONImage * image = [MONImage imageNamed:name]; 

imageNamed:私のサブクラス型のオブジェクトを返しますか?

+[UIImage imageNamed:]の実装はこのアプローチからサブクラスを書きました。したがって、このメソッドを自分で実装する必要があります。

+ (instancetype)imageNamed:(NSString *)pName; 

とどのように1 それを実装する必要があります: - +[UIImage imageNamed:]は書い

+ (instancetype)imageNamed:(NSString *)pName 
{ 
    MONImage * image = [[self alloc] initWithThisDesignatedInitializer:pName]; 
         ^^^^ NOTE: self, not a concrete class 
    ...set up image... 
    return image; 
} 

をしかし、彼らはそのようにしませんでした。ここ

は1 ファクトリメソッドを宣言する必要があります方法ですサブクラスを返し、MONImage * img = [MONImage imageNamed:pName];と書くとUIImageを返します。時にはそれは良い理由のために行われます。いくつかのメソッドは「最終的な」セマンティクスを持つ必要があります。これは、クラスクラスターのように、メソッドが複数の型を返すことがある場合によく表示されます。言語は「最終的な」方法を表現しませんが、そのような方法は少なくとも文書化されるべきです。

@interface MONImage : UIImage 

+ (instancetype)imageNamed:(NSString *)pName; 

@end 

@implementation MONImage 

+ (instancetype)imageNamed:(NSString *)pName 
{ 
    UIImage * source = [UIImage imageNamed:pName]; 
    CGImageRef cgImage = source.CGImage; 
    if (cgImage) 
     return [[self alloc] initWithCGImage:cgImage]; 
    // try it another way 
    return nil; 
} 

@end 

UIImage sおよびCGImage sが不変であること:これUIImage場合に周りに来て


。これにより、画像データのディープコピーが作成されるべきではありません。

+2

+1はinstancetypeを使用しています。 – Abizern

+2

これは '[UIImage imageNamed:]'のキャッシングビヘイビアも提供しますか?もしそうでなければ、元のイメージへの参照を 'MONImage'に保存するべきでしょう。しかし、本当に素晴らしい解決策。 –

+0

@JonathanCichon '+ imageNamed:'の検索動作を保持します。イメージをロードしてからキャッシュします。キャッシングの実装の正確な振る舞いは抽象化されているので、私の結論は、この点で同一であることが保証されていないということです。私はキャッシングに関して同じであると仮定しますが、私はそれを証明していません。良い質問。 – justin

2

  • サブクラスUIImage
  • MyImage、たとえば、にあなたが行われる必要があることを具体的な何かをするimageNamed:メソッドを実装します。
  • コールそのクラスにそのメソッド:私の問題を解決しMyImage *newImage = [MyImage imageNamed:imageName];
+2

これは実際には役に立ちません。あなた自身の 'imageNamed'の実装で' super'を呼び出すことができないので、これは 'UIImage'型のインスタンスを返すことになります。 –

+0

彼はスーパーに電話する必要があると誰が言いますか?メソッド内でサブクラスのオブジェクトを割り当てて初期化し、それを返すことができます。そして皆さんが知っているように、このコンベンションでは、サブクラスがスーパークラスの指定された初期化子を呼び出すことがあります。この初期化子は、 'id'型のオブジェクトを返します。とにかく、これは、OPが求めていたことに基づいて作られた実例です。詳細はユーザーに任せられますが、便利なコンストラクターの原則は、自分自身のクラスのオブジェクトをallocしてinit'ingすることは健全です。 – Abizern

+1

はい、この場合、「マジック」リンゴは 'imageNamed:'にありますが、これは非常に便利で、私は自分でこれを実装したいと思っていません。しかし、あなたは正しいです、あなたの答えは「間違っていません」しかし、私はこのケースではあまり役に立たないと思います。 –

0

アプローチは、(クレジットは私の質問のコメントでジョナサンCichonに行く)相続の代わりにカテゴリを使用することでした。私はAssociative Referencesを使用して、ここで多く議論されているように、カテゴリの実装に追加データを宣言して格納します。 Jonathanによって提案されたNSObject category implementationに注目して、本当に簡単でエレガントにして、どのオブジェクトにも関連参照を追加するようにしたいと思います。

+0

私はあなたの問題を解決してうれしいですが、あなたの質問は便利なコンストラクタをオーバーライドすることでした。次に、クラス拡張の外のクラスにストレージを追加する質問に変更しました。実際には2つの質問と回答が同時に行われます。 – Abizern

+0

元のフレームワーククラスを追加のデータで拡張し、元の便利なコンストラクタを使用できるようにする必要がありました。私が元の質問をしたとき、私はこれをどうやって行うのか分からず、継承で達成できると考えました。あなたは、私がクラスに追加のデータを追加する必要があることを正確には指定せず、 "継承"を書いたという観点からは正しいです。一方、継承を使用しない場合でも、ジョナサンのソリューションは私の問題を完全に解決します。 – MrTJ

+0

注:私は元の質問を変更せず、この答えのassoc.refsのヒントを将来の読者の参考としてのみ追加しました。 – MrTJ