2010-12-08 9 views
4

私はMail.app用のプラグインの作成に取り組んでいます。私は、プラグインがMailのツールバーにボタンを追加したいと思います。これを行うために、MessageViewerのinitializeメソッド(MessageViewerはMail.appのFirstResponderのクラス)にこのボタンを追加する関数を呼び出すのが最善の方法と判断しました。私は変更していたコードはうまく動作しているようです。しかしクラスメソッドをswizzleできません。

+ (void) initialize 
{ 
[super initialize]; 

// class_setSuperclass([self class], NSClassFromString(@"MVMailBundle")); 
// [ArchiveMailBundle registerBundle]; 


// Add a couple methods to the MessageViewer class. 
Class MessageViewer = NSClassFromString(@"MessageViewer"); 

// swizzleSuccess should be NO if any of the following three calls fail 
BOOL swizzleSuccess = YES; 
swizzleSuccess &= [[self class] copyMethod:@selector(_specialValidateMenuItem:) 
           fromClass:[self class] 
            toClass:MessageViewer]; 
swizzleSuccess &= [[self class] copyMethod:@selector(unsubscribeSelectedMessages:) 
           fromClass:[self class] 
            toClass:MessageViewer]; 

、私は同じことをしようとすると、それは動作しません。ここで

// //Copy the method to the original MessageViewer 
swizzleSuccess &= [[self class] copyMethod:@selector(_specialInitMessageViewer:) 
           fromClass:[self class] 
            toClass:MessageViewer]; 

は、スウィズリング方法です:

+ (BOOL)swizzleMethod:(SEL)origSel withMethod:(SEL)altSel inClass:(Class)cls 
{ 
// For class (cls), swizzle the original selector with the new selector. 
    //debug lines to try to figure out why swizzling is failing. 
// if (!cls || !origSel) { 
    //   NSLog(@"Something was null. Uh oh."); 
    //} 
Method origMethod = class_getInstanceMethod(cls, origSel); 

if (!origMethod) { 
    NSLog(@"Swizzler -- original method %@ not found for class %@", NSStringFromSelector(origSel), 
      [cls className]); 
    return NO; 
} 
    //if (!altSel) NSLog(@"altSel null. :("); 
Method altMethod = class_getInstanceMethod(cls, altSel); 
if (!altMethod) { 
    NSLog(@"Swizzler -- alternate method %@ not found for class %@", NSStringFromSelector(altSel), 
      [cls className]); 
    return NO; 
} 

method_exchangeImplementations(origMethod, altMethod); 

return YES; 

} 


+ (BOOL) copyMethod:(SEL)sel fromClass:(Class)fromCls toClass:(Class)toCls 
{ 
    // copy a method from one class to another. 
    Method method = class_getInstanceMethod(fromCls, sel); 
    if (!method) 
    { 
     NSLog(@"copyMethod-- method %@ could not be found in class %@", NSStringFromSelector(sel), 
       [fromCls className]); 
     return NO; 
    } 
    class_addMethod(toCls, sel, 
        class_getMethodImplementation(fromCls, sel), 
        method_getTypeEncoding(method)); 
    return YES; 
} 

私はログにエラーがあるので、class_getInstanceMethodの呼び出しで失敗しているようです。これは、自分自身のクラス内のメソッドと、MessageViewerのinitializeメソッドの両方で発生します。

私はここで考慮していないいくつかの問題はありますか?

+0

コードが正しくフォーマットされておらず、ちょっと混乱しているようです。あなたは少なくとも4つのスペースで意図されるように各コードラインを必要とします。 –

答えて

5

スウィズルを手動で実装する代わりに、JRSwizzleを使用してください。つまり、+jr_swizzleClassMethod:withClassMethod:error:のJRSwizzleの実装は単なるスタブですが、代わりに+jr_swizzleMethod:withMethod:errorをクラスのメタクラスに呼び出すことができます(klassの代わりにklass->isaを渡すだけです)。)klassは、あなたがうっとりしているクラスです)。

+0

ありがとう、ケビン、JRSwizzleパッケージはすごく見える!今、クラスメソッドをクラスにコピーする責任がありますか、それともjr_swizzleClassMethodコールでこれを示すことができるのでしょうか? (明白な場合は私の謝罪、私はObjCの新機能です) – Aaron

+0

'jr_swizzleMethod:withMethod:error:'はあなたのためにすべてを処理します。あなたのメソッドをターゲットクラスにコピーし、オーバーライドしようとしているメソッドでIMPを入れ替えます。 –

+0

さて、クラスFooにメソッドnewMethodがあり、それをクラスbarのメソッドorigMethodでうまくいきたいとします。どのクラスのどのメソッドを切り替えているのかをどのようにして通知するのですか? – Aaron

9

クラスメソッドをうまくいきたいのであれば、なぜclass_getClassMethod()の代わりにclass_getInstanceMethod()関数を使用していますか?

関連する問題