Pergunta

Eu gostaria de substituir um método em uma classe Objective C que eu não tenho a fonte de.

Eu olhei para ele, e parece que categorias devem permitir-me a fazer isso, mas eu gostaria de usar o resultado do método antigo no meu novo método, usando super para obter resultado os métodos antigos.

Sempre que eu tento isso, porém, o meu método é chamado, mas "super" é nulo ... Qualquer ideia porquê? Eu estou fazendo o desenvolvimento do iPhone com o Xcode 2.2 SDK. Eu definitivamente estou trabalhando com uma instância de uma classe, e o método da classe é um método de instância.

@implementation SampleClass (filePathResolver)
-(NSString*) fullPathFromRelativePath:(NSString*) relPath
{
    NSString *result = [super fullPathFromRelativePath: relPath];

  ... do some stuff with the old result

    return result;
}

Note e esclarecimento:? Do que eu posso ver no Apple Docs, parece-me que este deve ser permitido

Categorias docs em developer.apple.com: Quando uma categoria substitui um método herdado, o método no categoria pode, como de costume, invocar o implementação herdada através de uma mensagem a super. No entanto, se uma categoria substituições de um método que já existia na classe da categoria, há há nenhuma maneira de invocar o original implementação.

Foi útil?

Solução

Categorias estender a classe original, mas eles não subclasse-lo, portanto, uma chamada para super não encontrar o método.

O que você quer é chamado Método Swizzling . Mas esteja ciente de que seu código pode quebrar alguma coisa. Há um artigo sobre Theocacao escrito por Scot Stevenson sobre Método Swizzling no antigo tempo de execução Objective-C, Cacau com amor por Matt Gallagher tem um artigo sobre o método Swizzling no novo objectivo -C 2.0 tempo de execução e uma substituição simples para ele.

Como alternativa, você poderia subclasse da classe e, em seguida, usar o subclasse ou uso + (void)poseAsClass:(Class)aClass para substituir a superclasse. escreve Apple:

Um método definido por uma classe posar pode, através de uma mensagem para super, incorporar a ele método superclasse substituições.

Esteja ciente de que a Apple tem depreciado poseAsClass: no Mac OS X 10.5.

Outras dicas

Se você vai ser codificação contra esta classe, simplesmente mudar o nome do seletor para algo que seu código pode usar, e chamar o seletor original no self:

@implementation SampleClass (filePathResolver)
-(NSString*) myFullPathFromRelativePath:(NSString*) relPath
{
    NSString *result = [self fullPathFromRelativePath: relPath];

  ... do some stuff with the old result

    return result;
}

Se você quiser substituir a implementação padrão deste seletor para essa classe, você vai precisar usar o método swizzling abordagem .

Não exatamente na categoria, mas há uma solução alternativa adicionando o método dinamicamente em tempo de execução. Samuel Défago em seu artigo descreve uma maneira pura para criar bloco de implementação IMP chamando super, seu artigo original pode ser encontrada aqui

O código relevante é:

#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);
Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top