web-dev-qa-db-fra.com

Substitution de méthodes à l'aide de catégories dans Objective-C

Puis-je utiliser une catégorie de classe pour remplacer une méthode qui est déjà implémentée à l'aide d'une catégorie? Comme ça:

1) Méthode originale

-(BOOL) method {
  return true;
}

2) Méthode remplacée

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

Est-ce que cela fonctionnera ou est-ce illégal?

86
retix

De documentation Apple :

Bien que le langage Objective-C vous permette actuellement d'utiliser une catégorie pour remplacer les méthodes dont la classe hérite, ou même les méthodes déclarées dans l'interface de classe, vous êtes fortement déconseillé de le faire . Une catégorie ne remplace pas une sous-classe. Il existe plusieurs lacunes importantes dans l'utilisation d'une catégorie pour remplacer les méthodes:

  • Lorsqu'une catégorie remplace une méthode héritée, la méthode de la catégorie peut, comme d'habitude, appeler l'implémentation héritée via un message à super. Cependant, si une catégorie remplace une méthode qui existe dans la classe de la catégorie, il n'y a aucun moyen d'invoquer l'implémentation d'origine .

  • Une catégorie ne peut pas remplacer de manière fiable les méthodes déclarées dans une autre catégorie de la même classe.

    Ce problème est particulièrement important car de nombreuses classes Cocoa sont implémentées à l'aide de catégories. Une méthode définie par le framework que vous essayez de remplacer peut elle-même avoir été implémentée dans une catégorie et l'implémentation qui a la priorité n'est donc pas définie.

  • La présence même de certaines méthodes de catégorie peut entraîner des changements de comportement dans tous les frameworks. Par exemple, si vous remplacez le windowWillClose: méthode déléguée dans une catégorie sur NSObject, tous les délégués de fenêtre de votre programme répondent ensuite en utilisant la méthode catégorie; le comportement de toutes vos instances de NSWindow peut changer. Les catégories que vous ajoutez à une classe d'infrastructure peuvent provoquer de mystérieux changements de comportement et entraîner des plantages.

142
Benoît

Vous pouvez le faire en adaptant l'approche Cluster de classes , ou en utilisant la technique swizzling des méthodes .

Sinon, le comportement de deux ou plusieurs méthodes catégorisées est non défini

18
Martin Babacaev

L'ancien lien de documentation est mort; le meilleur remplacement que j'ai pu trouver était ici: Apple Docs :

Évitez les conflits de nom de méthode de catégorie

Étant donné que les méthodes déclarées dans une catégorie sont ajoutées à une classe existante, vous devez faire très attention aux noms de méthode.

Si le nom d'une méthode déclarée dans une catégorie est identique à une méthode de la classe d'origine ou à une méthode d'une autre catégorie de la même classe (ou même d'une superclasse), le comportement n'est pas défini quant à l'implémentation de la méthode utilisée à exécution. Cela est moins susceptible de poser un problème si vous utilisez des catégories avec vos propres classes, mais peut poser des problèmes lors de l'utilisation de catégories pour ajouter des méthodes aux classes Cocoa ou Cocoa Touch standard.

C'est Apple en utilisant une touche plus légère, mais le point principal est le même: vous invitez au désastre, car le comportement imprévisible est silencieux.

8
AmitaiB

Il est important de noter qu'une catégorie peut également être utilisée pour remplacer les méthodes existantes dans la classe de base (par exemple, la méthode de conduite de la classe Car), mais vous ne devriez jamais le faire. Le problème est que les catégories sont une structure organisationnelle plate. Si vous remplacez une méthode existante dans Car + Maintenance.m, puis décidez de modifier à nouveau son comportement avec une autre catégorie, Objective-C n'a aucun moyen de savoir quelle implémentation utiliser. Le sous-classement est presque toujours une meilleure option dans une telle situation.

De ce tutoriel, http://rypress.com/tutorials/objective-c/categories

2
Vinuta