ObjCでは、プロトコルを使用して動作を制限できるため、値または非変数をとして提供するまでは非常にうまく機能id
するようなものを宣言でき
ますが、プロトコル指定子なしで削除された汎用変数を渡すことができるため、これは完全に壊れます。 ..これは正常ですか?回避策はありますか?私は何かが足りないのですか?-(void)aMethod:(id<aProtocol>)aVar
id
aVar
id
3 に答える
使用id
量を減らし、可能な場合は正しい型を使用して変数とパラメーターを宣言します。つまり、id
sを渡さないでください。たとえば、コレクションクラスを実装している場合は、id
が役立つことがよくあります。
私のアプローチは、タイプを指定し、そのタイプをソースで可能な限りローカルに導入することです。したがって、型を省略id
して追加し、(たとえば)コレクションから参照を取得するときに、変数を作成します。
MONType<MONProtocol>* thing = [array objectAtIndex:idx];
// now thing is correctly typed. use thing.
同様に、id
パラメーターがある場合は、新しい変数を宣言します。
- (IBAction)someAction:(id)sender
{
NSButton * button = sender;
// now use button, not sender
プロトコルは非常に便利です。非常に多くの場合、サブクラス化よりも優れています。
Objective-Cのタイプは、コンパイル時ではなく実行時に決定されるという理解が欠けています。オブジェクトが型になると言ったからといって、id<aProtocol>
実行時にそうなることが保証されているわけではありません。
何かを指定するという考えはid<aProtocol>
、開発者やコードを使用する人々を支援するためのものです。想定されるタイプのインスタンスには存在しないとコンパイラーが判断できるものでメソッドを呼び出そうとすると、コンパイラーが警告(またはARCではエラー)するため、開発者として役立ちます(転送を意味する可能性がある転送を除く)インスタンスは、コンパイラが判断できないものに応答します)。それは彼らがあなたのコードとインターフェースするときに彼らが従うべき契約を彼らに告げるのであなたのコードを使う人々を助けます。
だから、あなたの質問であなたはそれを言います:
しかし、プロトコル指定子なしで削除された汎用ID変数を渡すと、これは完全に壊れます。
コンパイラは、を渡す場合を除いて、そのプロトコルに準拠していないものを渡そうとしていることを警告して通知しますid
。そのため、通常は、単に。よりも正確に入力する必要がありますid
。
次のように定義されたメソッドがある場合:
- (void)aMethod:(id<aProtocol>)aVar
次に、それが次のように定義されているaVar
タイプである可能性があります。SomeSubclass
@interface SomeSubclass : NSObject <aProtocol>
そして、次のように使用できますaMethod
。
SomeSubclass *obj = [SomeSubclass new];
[other aMethod:obj];
私は(ついに)Objective-C++を使用することが道であることに気づきました。NSString
またはNSNumber
(あまりにも一般的すぎて、値id
を渡すのに役に立たないプロトコルを使用する代わりに)渡すことができるようにしたいとしますid
:まあ、ObjCクラスごとに1つずつ、2つの異なるコンストラクターを持つC++クラスを作成できます。id
値はもう(ほとんど直接)実行できません。たとえば、見てみましょう
class NSStringOrNSNumber{
public:
NSStringOrNSNumber(NSString *);
NSStringOrNSNumber(NSNumber *);
};
NSStringOrNSNumber
コンストラクターは暗黙のキャストとして機能するため、パラメーターを受け取るメソッド/関数がNSString/NSNumber値を直接取得できるという大きな利点があります。言い換えれば、
void aFunction(NSStringOrNSNumber param);
次の呼び出しは完全に有効です。
aFunction(@"Hello!");
aFunction(@25);
唯一の(小さな)欠点は、コンストラクターに渡された値を取得する場合に、関数を実装するためのクラスが必要になることです。
C ++クラスコンストラクターを使用して次のようなものを取得する方が、直接id<NSCoding>
使用する方が優れていid<NSCoding>
ます。実際、次のようにすると、
@class classOne, classTwo;
class NSCodingClass{
private:
NSCodingClass(classOne *);
NSCodingClass(classTwo *);
public:
NSCodingClass(id<NSCoding>);
}
ジェネリックをパラメーターとして渡すことはできませんid
(あいまいなため、コンパイラーは2つのプライベートコンストラクターの中でどちらのコンストラクターを呼び出すかを知ることができません)