2016-06-12 10 views
3

メソッドの具体的な実装を(オーバーライドされていても)カテゴリから呼び出す必要があります。出来ますか? (念のために:は、私が知っている、Objective-Cの中のすべてのメソッドは、仮想です。)これはあなたの問題を解決することがありObjective-Cの非仮想メソッド

// class A 
@interface A 

- (void)foo; 

@end 

@implementation A 

- (void)foo 
{ 
    NSLog(@"initial foo"); 
} 

@end 

// subclass of A 
@interface A1: A 

@end 

@implementation A1 

- (void)foo 
{ 
    NSLog(@"overridden foo"); 
} 

@end 

// category to A 
@interface A (Category) 

- (void)bar; 

@end 

@impletemtation A (Category) 

- (void)bar 
{ 
    [self foo]; // probably, I should specify here what exactly must be self 
        // but I don't know how 
} 

@end 

///////////////////////////////////////////////////////////////// 
A1 *a = [[A1 alloc] init]; 

[a bar]; // now the "overridden foo" string will be printed 
      // my goal is to print "initial foo" !!! 
+3

あなたは本当にそのようなカプセル化を破るしますか? – Sulthan

+0

まだ分かりません。それにもかかわらず、私は理論的に可能かどうかを知りたいと思っています。 –

+0

これは巨大なコードの臭いですが、あなたは '[super foo];を試しましたか? – vikingosegundo

答えて

3

のもちろん、何も変更する必要はありません。

あなたは、特定のクラスのすべてのメソッドの実装に関数ポインタを取得することができます:

A* receiver = … 
IMP impOnA = class_getMethodImplementation([A class], @selector(foo)); 
((void (*)(id, SEL))impOnA)(receiver, @selector(foo)); // or whatever signature 
+0

答えを少し更新するといいですね。コンパイラは複数のパラメータを持つ関数名としてimpOnAを使用させることはできません。** void(* imp)(id、SEL)**に変換する必要があります。ありがとう、それはエレガントなソリューションです。 –

+0

もちろん、あなたは正しいです。関数ポインタをキャストする必要があります。 (申し訳ありません、Safariで入力しました)私はそれを追加しました。 –

+0

ああ、あなたはウクライナ出身です。今夜は良い試合をしましょう - とドイツの勝利。 ;-) –

-1

:最後に

// class A 
@interface A 

- (void)foo; 

@end 

@implementation A 

- (void)foo 
{ 
    [self fooImpl]; 
} 

- (void)fooImpl 
{ 
    NSLog(@"initial foo"); 
} 

@end 

// subclass of A 
@interface A1: A 

@end 

@implementation A1 

- (void)foo 
{ 
    NSLog(@"overridden foo"); 
} 

@end 

// category to A 
@interface A (Category) 

- (void)bar; 

@end 

@impletemtation A (Category) 

- (void)bar 
{ 
    [self fooImpl]; // probably, I should specify here what exactly must be self 
        // but I don't know how 
} 

@end 

///////////////////////////////////////////////////////////////// 
A1 *a = [[A1 alloc] init]; 

[a bar]; // now the "overridden foo" string will be printed 
      // my goal is to print "initial foo" !!! 
+0

残念ながら、私はそれをすることはできません。私の場合、AはUIViewControllerであり、実装を書き直すことはできません。 –

0

@implementation A (Category) 

- (void)quux 
{ 
    NSLog(@"quux"); 
} 

- (void)bar 
{ 
    Class class = [A class]; 

    SEL originalSelector = @selector(foo); 
    SEL swizzledSelector = @selector(quux); 

    Method originalMethod = class_getInstanceMethod(class, originalSelector); 
    Method swizzledMethod = class_getInstanceMethod(class, swizzledSelector); 

    method_exchangeImplementations(originalMethod, swizzledMethod); 
    [self quux]; 
    method_exchangeImplementations(originalMethod, swizzledMethod); 
} 

@end 
+0

意図してくれてありがとうございますが、問題は解決しません。ここでは実装を一時的に置き換えますが、必要はありません。私が必要とするのは、呼び出されるクラスAのメソッドfooだけです。 –

2

を作品swizzing確かに方法あなたが起動したい具体的な方法を見つけるために、Matt Gallagher's supersequent implementation approachを適応させることができます。また、あなただけの一時的クラスを設定することができ

Class realClass = object_getClass(self); 
Class fakeClass = [A class]; 

object_setClass(self, fakeClass); 
[self foo]; 
object_setClass(self, realClass); 

を(私は自分の携帯電話によ、そう構文約100%確実ではないが、アイデアは動作するはずです。)

+0

特定の実装を選択したいが、オブジェクトのクラスは変更しない。これは '-foo'の実装に害を与えるかもしれません。 –

+1

あなたはどんな害を特に意味しますか? –

関連する問題