Domanda

Sto cercando di modificare il comportamento di un programma (non ho la sua fonte) usando SIMBL. Ho usato il dump di classe e ho scoperto che ho bisogno di un metodo di istanza

Questo metodo è nella classe chiamata controller. Tutto quello che devo fare è ottenere l'argomento arg1 e questo è tutto. Forse NSLOG IT o POST di una notifica ... Ho letto del metodo Swizzling in Objective-C ma come posso usarlo?. Avrei bisogno di fare riferimento al MessageController di classe il cui corso non ho.

Grazie!

È stato utile?

Soluzione

Immagino che tu debba chiamare l'implementazione originale dopo aver fatto il tuo NSLog; In caso contrario, potresti essere in grado di utilizzare solo una categoria sulla classe per sovrascrivere il metodo.

Per ridotto il metodo, prima è necessario un metodo di sostituzione. Di solito metto qualcosa di simile in una categoria nella classe target:

- (void)replacementReceiveMessage:(const struct BInstantMessage *)arg1 {
    NSLog(@"arg1 is %@", arg1);
    [self replacementReceiveMessage:arg1];
}

Sembra che si chiamerà ricorsivamente, ma non lo farà perché scambieremo le cose, quindi chiameremo ReceiveMessage: chiamate questo metodo mentre chiama replacementReceiveMessage: chiama la vecchia versione.

Il secondo passo è utilizzare le funzioni di runtime per eseguire effettivamente lo scambio. Il vantaggio di utilizzare una categoria è che puoi usare load Nella categoria per fare il lavoro:

+ (void)load {
    SEL originalSelector = @selector(ReceiveMessage:);
    SEL overrideSelector = @selector(replacementReceiveMessage:);
    Method originalMethod = class_getInstanceMethod(self, originalSelector);
    Method overrideMethod = class_getInstanceMethod(self, overrideSelector);
    if (class_addMethod(self, originalSelector, method_getImplementation(overrideMethod), method_getTypeEncoding(overrideMethod))) {
            class_replaceMethod(self, overrideSelector, method_getImplementation(originalMethod), method_getTypeEncoding(originalMethod));
    } else {
            method_exchangeImplementations(originalMethod, overrideMethod);
    }
}

Ci sono due casi che devono essere gestiti:

  • Se il metodo che stiamo swizzling è effettivamente definito in una superclasse, dobbiamo usare class_addMethod Per aggiungere un'implementazione di ReceiveMessage: alla classe target, che facciamo utilizzando la nostra implementazione di sostituzione. Quindi possiamo usare class_replaceMethod Rimpiazzare replacementReceiveMessage: Con l'implementazione della Superclass, quindi la nostra nuova versione sarà in grado di chiamare correttamente il vecchio.
  • Se il metodo è definito nella classe target, class_addMethod fallirà ma poi possiamo usare method_exchangeImplementations Per scambiare le versioni nuove e vecchie.

Altri suggerimenti

La Biblioteca jrsswizzle gestiscelo. Farlo da solo non è consigliato, perché ci sono molti dettagli per ottenere bene. (Vedi la tabella che documenta i guasti delle precedenti implementazioni in JRSWizzle Readme.)

Supponi di avere una classe come questa:

@interface Weh : NSObject
-(void)foo;
-(void)bar;
@end

@implementation Weh
-(void)foo {
    NSLog(@"Foo called");
}
-(void)bar {
    NSLog(@"Bar called");
    [self bar];
}
@end

Puoi usarlo in questo modo:

Weh *weh = Weh.new;
[weh foo];
[Weh jr_swizzleMethod:@selector(foo) withMethod:@selector(bar) error:nil];
[weh foo]; 

Produzione:

Foo called
Bar called
Foo called
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top