なぜメソッドのシグネチャで使用(ID)と(NSObjectの*)は、より正確でしょうか?

StackOverflow https://stackoverflow.com/questions/1829028

  •  11-09-2019
  •  | 
  •  

質問

私は、複数のクラスのオブジェクトを受け入れるか返すことができ、私自身のコード内のメソッドを実装するたびに

、私は常に最も具体的なスーパークラスを使用するようにしてください。私はその入力に応じたNSArray *またはNSDictionaryの*を返す場合がありますメソッドを実装するつもりだった場合には、最も直接的な共通のスーパークラスですので、例えば、私は、その方法にはNSObject *の戻り値の型を与えるだろう。ここでは例があります:

@interface MyParser()
- (BOOL)stringExpressesKeyValuePairs:(NSString *)string;
- (BOOL)stringExpressesAListOfEntities:(NSString *)string;
- (NSArray *)parseArrayFromString:(NSString *)string;
- (NSDictionary *)parseDictionaryFromString:(NSString *)string;
@end

@implementation MyParser
- (NSObject *)parseString:(NSString *)string {
    if ([self stringExpressesKeyValuePairs:string]) {
        return [self parseDictionaryFromString:string];
    }
    else if ([self stringExpressesAListOfEntities:string]) {
        return [self parseArrayFromString:string];
    }
}
// etc...
@end
(NSObjectの*)は、より正確になるとき

私は財団とAppleは、特定のメソッドのシグネチャで(ID)を使用して他のAPIの多くの例を気づきました。例えば、ここでNSPropertyListSerializationの方法です。

+ (id)propertyListFromData:(NSData *)data 
          mutabilityOption:(NSPropertyListMutabilityOptions)opt 
                    format:(NSPropertyListFormat *)format 
          errorDescription:(NSString **)errorString

この方法から可能なリターンタイプがNSDataの、NSStringの、にNSArray、NSDictionaryの、NSDate、およびのNSNumberです。呼び出し側が、その後、型キャストせずに維持するようなNSObjectのメソッドを呼び出すことができるようになるので、(NSObjectの*)の戻り値の型は、(ID)よりも良い選択であるように私には思える。

私は、一般的に公式の枠組みによって確立されたイディオムをエミュレートしようとするが、私はまた、彼らの動機を理解したいです。私はAppleがこのような場合には(id)を使用するためのいくつかの正当な理由を持っていることを確信しているが、私はそれを見ていませんよ。私は何をしないのですか?

役に立ちましたか?

解決

IDを使用して、それは未知のタイプのオブジェクトになりますコンパイラに指示します。コンパイラは、あなたが唯一のNSObjectのに使用可能なメッセージを使用してすることが期待されるNSObjectのを使用します。あなたが知っている場合は、配列が返され、それをIDとしてキャストですので...、あなたはobjectAtIndexを呼び出すことができます。コンパイラの警告なし。 NSObjectののキャストで返すのに対し、あなたは警告を取得します。

他のヒント

(ID)は、メソッド宣言に使用されている理由は、2倍

(1)の方法は、任意の型を取るか、または返すことができます。 NSArrayのは、任意のランダムなオブジェクトが含まれており、したがって、objectAtIndex:は、任意のランダムな型のオブジェクトを返します。それはNSObject*またはid <NSObject>にキャストすると、2つの理由で正しくないだろう。まず、アレイは、彼らは方法の特定の小さなセットを実装して、第二に、特定の戻り値の型は、キャストを必要とする限り、非NSObjectのサブクラスを含めることができます。

(2)のObjective-Cは、共変の宣言をサポートしていません。考えてみます:

@interface NSArray:NSObject
+ (id) array;
@end

さて、あなたは+arrayNSArrayの両方にNSMutableArrayを呼び出すことができます。前者は不変配列と後者可変配列を返します。上記は(NSArray*)を返すように宣言された場合にはそのための共変宣言のサポートののObjective-Cの不足のため、サブクラスのメソッドのクライアントは `(NSMutableArrayの*)にキャストする必要があります。醜い、壊れやすい、とエラーが発生しやすいです。このように、ジェネリック型を使用すると、一般的に、最も簡単なソリューションです。

だから... ...あなたは明示的に型キャスト、特定のクラスのインスタンスを返すメソッドを宣言している場合。あなたが上書きされ、そのオーバーライドがをサブクラスを返すことがあります。そして、のそれはサブクラスを返すという事実をクライアントに公開されるメソッドを宣言している場合は、(id)を使用します。

<ストライキ>バグを提出する必要はありません - いくつかはすでに存在している

。 <時間>

にObjCは今instancetypeキーワードによって制限された共同分散をサポートしていることに注意します。

すなわち。 NSArrayの+アレイ法は、現在のように宣言することができます:

+ (instancetype) array;

とコンパイラは[NSMutableArray array]NSMutableArray*を返すとみなされるだろうが[NSArray array]を返すようNSArray*を扱います。

あなたはすでにキャストせずにid型のポインタに-retain呼び出すことができます。あなたが特定のスーパータイプを使用している場合、あなたはコンパイラの警告を避けるために、サブクラスのメソッドを呼び出すたびにポインタをキャストする必要があります。コンパイラは警告を表示しませんし、もっと自分の意図を意味するので、IDを使用します。

(ID)もしばしばより容易にサブクラス化されるオブジェクトを有効にするために戻されます。例えば、初期化と利便方法では、(ID)を返すことはそうする特別な理由がない限り、すべてのサブクラスがスーパークラスのメソッドをオーバーライドする必要がないことを意味します。

ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top