20

以下はObjectiveCで機能しています。

// Base Class in ClassA.h and ClassA.m
@interface ClassA : NSObject 
- (NSString *) myMethod;
@end
@implementation ClassA
- (NSString*) myMethod { return @"A"; }
@end

//Category in ClassA+CategoryB.h and ClassA+CategoryB.m
@interface ClassA (CategoryB) 
- (NSString *) myMethod;
@end
@implementation ClassA (CategoryB)
- (NSString*) myMethod { return @"B"; }
@end

問題は、ClassA.hをインポートしてメッセージを送信するだけの場合です。

[myClassA myMethod]; //returns B

なぜこれが戻ってくるのBですか?ClassA+CategoryBをインポートしていません

私が次のことをした場合、さらに総統:

// Base Class in ClassA.h and ClassA.m
@interface ClassA : NSObject 
- (NSString *) myMethod;
- (NSString *) mySecondMethod;
@end
@implementation ClassA
- (NSString*) myMethod { return @"A"; }
- (NSString *) mySecondMethod { return [self myMethod]; }
@end

//Category in ClassA+CategoryB.h and ClassA+CategoryB.m
@interface ClassA (CategoryB) 
- (NSString *) myMethod;
@end
@implementation ClassA (CategoryB)
- (NSString*) myMethod { return @"B"; }
@end

mySecondMethodを呼び出します。

ClassA *a = [[ClassA alloc] init];
NSLog(@"%@",[a myMethod]);

Bカテゴリの実装については(インポートがないため)誰も知りませんが、結果はまだ残りますか?!

Bカテゴリをインポートしていた場合にのみ戻ることを除いて、 ...

だからどんなヒントもありがたい。

4

3 に答える 3

40

Objective-C のメッセージングは​​動的です。つまり、カテゴリをインポートするかどうかは問題ではありません。オブジェクトはメッセージを受け取り、そのメソッドを実行します。

カテゴリがメソッドをオーバーライドしています。これは、ランタイムがそのオブジェクトにメッセージを送信すると、何をインポートしても、常にオーバーライドされたメソッドを見つけることを意味します。

カテゴリを無視したい場合は、それをコンパイルすべきではないため、コンパイラ ソースからカテゴリを削除できます。
代替手段はサブクラス化です。

これも読んでください:

カテゴリ メソッド名の衝突を避ける

カテゴリで宣言されたメソッドは既存のクラスに追加されるため、メソッド名には十分注意する必要があります。

カテゴリで宣言されたメソッドの名前が元のクラスのメソッド、または同じクラス (またはスーパークラス) の別のカテゴリのメソッドと同じである場合、どのメソッド実装が使用されているかについての動作は未定義です。ランタイム。独自のクラスでカテゴリを使用している場合、これが問題になる可能性は低くなりますが、カテゴリを使用して標準の Cocoa または Cocoa Touch クラスにメソッドを追加する場合に問題が発生する可能性があります。

したがって、前述のように、これはユーザー定義クラスでは発生する可能性が低いため、問題はありません。ただし、カテゴリを記述する代わりに、必ずサブクラス化を使用する必要があります

于 2013-01-10T13:57:30.633 に答える
10

Obj-C では、カテゴリを使用して既存のクラスにメソッドを追加できます。したがって、NSString にメソッドを追加すると、NSMutableString と、NSString または NSString のサブクラスを継承するすべてのクラスで、カテゴリ化されたメソッドを使用できます。

ただし、カテゴリをオーバーライドすることは避けてください。

どのメソッドが呼び出されるか 100% 確実ではありません。コンパイラに依存します。

アップルのドキュメントから。

現在、Objective-C 言語では、カテゴリを使用して、クラスが継承するメソッドをオーバーライドしたり、クラス インターフェイスで宣言されたメソッドをオーバーライドしたりすることができますが、そうしないことを強くお勧めします。カテゴリはサブクラスの代わりではありません。カテゴリを使用してメソッドをオーバーライドすることには、いくつかの重大な欠点があります。カテゴリが継承されたメソッドをオーバーライドする場合、通常どおり、カテゴリ内のメソッドはスーパーへのメッセージを介して継承された実装を呼び出すことができます。ただし、カテゴリがそのカテゴリのクラスに存在するメソッドをオーバーライドする場合、元の実装を呼び出す方法はありません。カテゴリは、同じクラスの別のカテゴリで宣言されたメソッドを確実にオーバーライドすることはできません。Cocoa クラスの多くはカテゴリを使用して実装されているため、この問題は特に重要です。オーバーライドしようとするフレームワーク定義のメソッド自体がカテゴリに実装されている可能性があるため、どの実装が優先されるかは定義されていません。一部のカテゴリ メソッドが存在するだけで、すべてのフレームワークで動作が変化する可能性があります。たとえば、NSObject のカテゴリで windowWillClose: デリゲート メソッドをオーバーライドすると、プログラム内のすべてのウィンドウ デリゲートがカテゴリ メソッドを使用して応答します。NSWindow のすべてのインスタンスの動作が変わる可能性があります。フレームワーク クラスにカテゴリを追加すると、不可解な動作の変化が発生し、クラッシュする可能性があります。NSObject のカテゴリでデリゲート メソッドを使用すると、プログラム内のすべてのウィンドウ デリゲートがカテゴリ メソッドを使用して応答します。NSWindow のすべてのインスタンスの動作が変わる可能性があります。フレームワーク クラスにカテゴリを追加すると、不可解な動作の変化が発生し、クラッシュする可能性があります。NSObject のカテゴリでデリゲート メソッドを使用すると、プログラム内のすべてのウィンドウ デリゲートがカテゴリ メソッドを使用して応答します。NSWindow のすべてのインスタンスの動作が変わる可能性があります。フレームワーク クラスにカテゴリを追加すると、不可解な動作の変化が発生し、クラッシュする可能性があります。

于 2013-01-10T14:01:44.323 に答える
2

コンパイルすることで、カテゴリで定義されたコードを暗黙的に含めました。

カテゴリ コードが実行されないようにする場合は、カテゴリ実装ファイルを削除して、ターゲットから削除する必要があります。あなたはそれを行うことができます

ターゲット -> ビルド フェーズ -> ソースのコンパイル

とはいえ、メソッドをオーバーライドするためにカテゴリを使用するべきではありません。これは非常に悪い習慣であり、カテゴリの目的ではありません。

于 2013-01-10T14:04:10.170 に答える