2016-04-12 6 views
5

わかりましたので、うまくいけば、誰かが私を啓発することができ、これは確かにベストプラクティスの質問のビットですが、私は右のそれを取得したい:NS_DESIGNATED_INITIALIZERを使用してinitをオーバーライドする方法は?

シナリオはかなり標準ですが、1つのひねりがあります 私はクラスを持っています私が書いたフレームワークはNSObjectから直接継承しています。それはかなりの引数を持つ指定された初期化子を持っています、そのほとんどはnonnullです。そのことはフレームワークの一部なので、私は明示的にNS_DESIGNATED_INITIALIZERマクロを使用しています(これは私が小さい個人的なアプリケーションでは必ずしもそうとは限りません)。 問題は、Xcodeが、init、つまりスーパークラスの指定された初期化子をオーバーライドするように警告するということです。しかしそれに加えて、私は私のと呼ぶことを要求します。私はできません。なぜなら、私はその議論に意味のあるデフォルトが足りないからです。 私は本当に "小さな" initで例外をスローしたくないです、私はむしろnilを返すのが好きです。

が警告を取り除くために、私はそうのような私のクラスの拡張で第2の指定initalizerとしてinitを追加しました:

@interface MyClassName() 
// some other stuff not relevant` 

-(nullable instancetype)init NS_DESIGNATED_INITIALIZER; 

@end 

を今、私は私が欲しかった安全だけreturn nil;オーバーライドinit方法ですることができますように。 つまり、私のドキュメント(私はappledocを使用しています)と拡張XCodeのコード補完は、initが実際に指定された初期化子である(つまり、誤って使用することはない) (単体テストでは、例えばこれが便利になるかもしれません)。

私の質問は次のとおりです。実際にプロダクションでこれを使用している人以外に、これを実現することなく喜んでメッセージをnilに喜んで送信するという危険性はありますか?これは、initで例外をスローする方が望ましいほんの少しのケースですか?

答えて

6

nilinitから返すだけではなく、呼び出すべきではないとのコメントを追加するのではなく、使用不可とマークする必要があります。

NSObjectの指定された初期化子を上書きしないという警告を無視するだけでなく、指定された初期化子の代わりにinitを呼び出そうとすると、コンパイル時エラーが生成されます。

これを行うには、NS_UNAVAILABLEマクロを使用するか、使用できない__attribute__this answer)のいずれかを使用します。 __attribute__を使用する利点は、コンパイラがユーザーに提示するメッセージを指定できることです。例えば

@interface Foo : NSObject 

-(instancetype) init __attribute__((unavailable("You cannot create a foo instance through init - please use initWithBar:"))); 

-(instancetype) initWithBar:(Bar*)bar NS_DESIGNATED_INITIALIZER; 

@end 

... 


Foo* fooA = [[Foo alloc] init]; // ERROR: 'init' is unavailable: You cannot create a foo instance through init - please use initWithBar: 

Foo* fooB = [[Foo alloc] initWithBar:[[Bar alloc] init]]; // No error 
+0

どうもありがとう、これは間違いなく好ましい方法です。私の場合は、私が定義していないいくつかのテストのために、私は 'nil'を返す必要がありますが、私は間違いなく' __attribute__'を使用しようとします。これは明らかに一般的なソリューションです。私は実際にあなたがリンクしているquestion7を見落としました。なぜなら、特にinitを「ちょっと」プライベートにしたくないからです。今upvoteするつもりです。 – Gero

関連する問題