Usando Super numa Objetivo Categoria C?
-
05-07-2019 - |
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.
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);