Substituindo métodos usando categorias em Objective-C

87

Posso usar uma categoria de classe para substituir um método que já foi implementado usando uma categoria? Como isso:

1) Método original

-(BOOL) method {
  return true;
}

2) Método substituído

-(BOOL) method {
  NSLog(@"error?"); 
  return true; 
}

Isso funcionará ou é ilegal?

retix
fonte

Respostas:

145

Da documentação da Apple :

Embora a linguagem Objective-C atualmente permita que você use uma categoria para sobrescrever métodos que a classe herda, ou mesmo métodos declarados na interface da classe, você é fortemente desencorajado a fazer isso . Uma categoria não substitui uma subclasse. Existem várias deficiências significativas no uso de uma categoria para substituir métodos:

  • Quando uma categoria substitui um método herdado, o método na categoria pode, como de costume, invocar a implementação herdada por meio de uma mensagem para super. No entanto, se uma categoria substituir um método que existe na classe da categoria, não há como chamar a implementação original .

  • Uma categoria não pode substituir com segurança métodos declarados em outra categoria da mesma classe.

    Esta questão é de particular importância porque muitas das classes Cocoa são implementadas usando categorias. Um método definido pela estrutura que você tenta substituir pode ter sido implementado em uma categoria e, portanto, qual implementação tem precedência não está definida.

  • A própria presença de alguns métodos de categoria pode causar mudanças de comportamento em todas as estruturas. Por exemplo, se você substituir o windowWillClose:método delegado em uma categoria em NSObject, todos os delegados de janela em seu programa responderão usando o método categoria; o comportamento de todas as suas instâncias de NSWindow pode mudar. As categorias que você adiciona em uma classe de estrutura podem causar mudanças misteriosas no comportamento e levar a travamentos.

Benoît
fonte
Obrigado, mas eu já sei disso. Só me pergunto se meu caso é legal ou não. Meu caso é um pouco diferente dos documentos. :)
retix
Por que é diferente? O doc diz que é legal SE o método original não estiver em uma categoria, mas fortemente desencorajado. Então você pode fazer isso ...
Benoît
1
Agradecido por seu Conselho. Eu sou pobre neste idioma. Recebi novas informações de você.
retix de
1
É correto substituir no método Category declarado e implementado na categoria da superclasse?
BergP
2
O link está quebrado, esta é a nova versão? developer.apple.com/library/ios/documentation/Cocoa/Conceptual/…
RndmTsk
18

Você pode fazer isso adaptando a abordagem de Cluster de Classes ou usando a técnica de swizzling de métodos .

Caso contrário, o comportamento de dois ou mais métodos categorizados é indefinido

Martin Babacaev
fonte
9

O link de documentação antigo está morto; O melhor substituto que pude encontrar foi aqui: Apple Docs :

Evite conflitos de nomes de métodos de categoria

Como os métodos declarados em uma categoria são adicionados a uma classe existente, você precisa ter muito cuidado com os nomes dos métodos.

Se o nome de um método declarado em uma categoria for o mesmo que um método na classe original, ou um método em outra categoria na mesma classe (ou mesmo uma superclasse), o comportamento é indefinido quanto a qual implementação de método é usada em tempo de execução. É menos provável que isso seja um problema se você estiver usando categorias com suas próprias classes, mas pode causar problemas ao usar categorias para adicionar métodos às classes Cocoa ou Cocoa Touch padrão.

É a Apple usando um toque mais leve, mas o ponto principal é o mesmo: você convida ao desastre, porque o comportamento imprevisível é silencioso.

AmitaiB
fonte
2

É importante observar que uma categoria também pode ser usada para substituir métodos existentes na classe base (por exemplo, o método drive da classe Car), mas você nunca deve fazer isso. O problema é que as categorias são uma estrutura organizacional plana. Se você sobrescrever um método existente em Car + Maintenance.m, e então decidir que deseja alterar seu comportamento novamente com outra categoria, não há como Objective-C saber qual implementação usar. Subclassificar quase sempre é a melhor opção em tal situação.

A partir deste tutorial, http://rypress.com/tutorials/objective-c/categories

Vinuta
fonte