Objective CカテゴリでSuperを使用していますか?
-
05-07-2019 - |
質問
ソースを持たないObjective Cクラスのメソッドをオーバーライドしたい。
調査しましたが、カテゴリでこれを行うことができるようですが、古いメソッドの結果を取得するためにsuperを使用して、新しいメソッドで古いメソッドの結果を使用したいと思います。
これを試すたびに、メソッドが呼び出されますが、「super」 nil ...理由は何ですか? XCode 2.2 SDKを使用してiPhone開発を行っています。私は間違いなくクラスのインスタンスで作業しており、クラスのメソッドはインスタンスメソッドです。
@implementation SampleClass (filePathResolver)
-(NSString*) fullPathFromRelativePath:(NSString*) relPath
{
NSString *result = [super fullPathFromRelativePath: relPath];
... do some stuff with the old result
return result;
}
注意と説明:Apple Docsで見ることができるものから、これは許可されるべきだと思われますか?
developer.apple.comのカテゴリドキュメント: カテゴリが継承されたメソッドをオーバーライドする場合、 カテゴリは、通常どおり、 メッセージを介した継承された実装 スーパーに。ただし、カテゴリ 既にメソッドをオーバーライドします カテゴリーのクラスに存在していた オリジナルを呼び出す方法はありません 実装。
解決
カテゴリは元のクラスを拡張しますが、サブクラスは作成しません。したがって、 super
を呼び出してもメソッドは見つかりません。
必要なものは Method Swizzling と呼ばれます。ただし、コードが何かを壊す可能性があることに注意してください。古いObjective-Cランタイムでのメソッドスウィズリングについて、 Scot Stevensonによって書かれたTheocacao に関する記事があります。 Matt Gallagherの愛を込めたCocoa には、新しいObjectiveのMethod Swizzlingに関する記事があります。 -C 2.0ランタイムとその単純な置き換え。
別の方法として、クラスをサブクラス化してからサブクラスを使用するか、 +(void)poseAsClass:(Class)aClass
でスーパークラスを置き換えます。 Appleの書き込み:
ポーズクラスによって定義されたメソッド
super
へのメッセージを通じて、 スーパークラスメソッドを組み込む オーバーライドします。
AppleはMac OS X 10.5で poseAsClass:
を廃止していることに注意してください。
他のヒント
このクラスに対してコーディングする場合は、セレクターをコードで使用できる名前に変更し、 self
で元のセレクターを呼び出します。
@implementation SampleClass (filePathResolver)
-(NSString*) myFullPathFromRelativePath:(NSString*) relPath
{
NSString *result = [self fullPathFromRelativePath: relPath];
... do some stuff with the old result
return result;
}
そのクラスのこのセレクターのデフォルトの実装をオーバーライドする場合は、スウィズリングメソッドアプローチ。
正確にはカテゴリに含まれていませんが、実行時にメソッドを動的に追加することで回避策があります。 Samuel Dé fagoは彼の記事で、スーパーを呼び出すブロックIMP実装を作成するきちんとした方法について説明しています。彼の元の記事はここ
関連するコードは次のとおりです:
#import <objc/runtime.h>
#import <objc/message.h>
const char *types = method_getTypeEncoding(class_getInstanceMethod(clazz, selector));
class_addMethod(clazz, selector, imp_implementationWithBlock(^(__unsafe_unretained id self, va_list argp) {
struct objc_super super = {
.receiver = self,
.super_class = class_getSuperclass(clazz)
};
id (*objc_msgSendSuper_typed)(struct objc_super *, SEL, va_list) = (void *)&objc_msgSendSuper;
return objc_msgSendSuper_typed(&super, selector, argp);
}), types);