2013-02-28 2 views
3

Je comprends que remplacer une méthode en utilisant une catégorie est une pratique découragée. Néanmoins, je dois faire face à un code qui fait cela. Quand j'ai couru le code suivant, j'ai été surpris que ma méthode de catégorie soit appelée dans les deux cas, mais en pensant à la façon dont l'éditeur de liens doit prendre une décision au moment de la liaison pour un symbole donné. Ma question: En supposant qu'aucune autre catégorie ne soit en jeu autre que celles que je crée, suis-je assuré que l'implémentation dans ma catégorie sera toujours la logique qui est appelée tant que l'en-tête est importé de quelque part?Une méthode substituée dans une catégorie aura-t-elle toujours la priorité sur l'implémentation d'origine?

someObject.h

#import <Foundation/Foundation.h> 

@interface SomeObject : NSObject 

- (void)doSomething; 

@end 

someObject.m

#import "SomeObject.h" 

@implementation SomeObject 

- (void)doSomething 
{ 
    NSLog(@"Original"); 
} 

@end 

someObject + Cat.h

#import <Foundation/Foundation.h> 

#import "SomeObject.h" 

@interface SomeObject (SomeObject) 

- (void)doSomething; 

@end 

someObject + Cat.m

#import "SomeObject+Cat.h" 

@implementation SomeObject (SomeObject) 

- (void)doSomething 
{ 
    NSLog(@"New!"); 
} 

@end 

someObjectUser.h

#import <Foundation/Foundation.h> 

@interface SomeObjectUser : NSObject 

- (void)useSomeObject; 

@end 

someObjectUser.m

#import "SomeObjectUser.h" 

#import "SomeObject.h" 

@implementation SomeObjectUser 

- (void)useSomeObject 
{ 
    [[SomeObject new] doSomething]; 
} 

@end 

Test.m

- (void)testExample 
{ 
    [[SomeObject new] doSomething]; 
    [[SomeObjectUser new] useSomeObject]; 
} 

Résultat

2013-02-28 11:32:37.417 CategoryExample[933:907] New! 
2013-02-28 11:32:37.419 CategoryExample[933:907] New! 
+0

@NikolaiRuhe Je ne suis pas d'accord, les questions sont fondamentalement différentes. –

+0

@MikeD La question est un peu différente mais la réponse est valide pour les deux questions. – Sulthan

+0

J'ai d'abord lu cette question et je peux maintenant voir comment il y a une réponse, mais le fait que le guide dise que le comportement indéfini est "moins susceptible d'être un problème" m'a fait me demander s'il y avait des idées supplémentaires ici. –

Répondre

5

En supposant aucune autre catégorie sont en jeu autres que ceux que je crée, suis-je garantis que la mise en œuvre dans ma catégorie sera toujours la logique qui est appelée aussi longtemps que l'en-tête est importé de quelque part?

Je doute que cela ait de l'importance si vous importez ou non l'en-tête de catégorie. Les en-têtes sont des informations pour le compilateur; Les catégories sont ajoutées aux classes au moment de l'exécution et la sélection de l'implémentation utilisée pour une méthode donnée a lieu au moment de l'exécution. Plus important encore ...

De Objective-C Programming Guide:

Si le nom d'une méthode déclarée dans une catégorie est le même comme méthode dans la classe d'origine, ou une méthode dans une autre catégorie sur le même classe (ou même une superclasse), le comportement est indéfini pour lequel l'implémentation de la méthode est utilisée au moment de l'exécution. Ceci est moins susceptible d'être un problème si vous utilisez des catégories avec vos propres classes, mais peut causer des problèmes lors de l'utilisation de catégories pour ajouter des méthodes à Cocoa standard ou classes Cocoa Touch.

(moi qui souligne.)

Compte tenu de l'utilisation du mot non défini, je dirais que la réponse à la question est non, il n'y a aucune garantie dont la mise en œuvre sera utilisé lorsque vous ré-implémentez une méthode existante dans une catégorie. En pratique, si la classe est la vôtre, alors la méthode de votre catégorie sera très probablement sélectionnée, et j'espère que cela sera fiable si cela fonctionne dans le test d'une version donnée du compilateur et de l'exécution.

+0

Bizarre! À moins que je ne sois fou, c'est un changement radical par rapport à l'ancien comportement, à savoir que les catégories remplacent toujours les méthodes non catégorielles, mais il n'y avait aucun moyen de faire en sorte qu'une catégorie prenne la priorité sur une autre. Bonne prise. – Chuck

+0

Salut, @Chuck. Je ne pense pas que quelque chose ait vraiment changé - puisque les méthodes de catégories sont nécessairement ajoutées à la classe après la création de la classe, je m'attends à ce que l'implémentation de la catégorie soit toujours utilisée. Mais le PO a demandé une * garantie *, évidemment un terme fort, et les docs disent * undefined *, donc ... – Caleb

+0

Aussi de la documentation: "Une méthode définie par le framework que vous essayez de remplacer peut elle-même avoir été implémentée dans un catégorie, et donc quelle implémentation a priorité n'est pas définie. " Si ce n'était pas défini dans tous les cas, pourquoi feraient-ils tout leur possible pour le dire? Je questionne la documentation sur ce ... –

0

MISE À JOUR:

Dans la réponse SO lien ci-dessous, le lien pointant vers la catégorie Objective-C docs est mort. Here is more up to date version. Il y a une section sur la façon d'éviter les conflits de noms.


Oui, selon ce SO answer, (je posterai le lien officiel d'Apple quand je trouve).

Certains avertissements, la méthode d'origine sera inaccessible mais vous pouvez toujours passer à super, il n'y a aucune garantie qu'une méthode déclarée dans une autre catégorie (sur la même classe) sera remplacée.

Questions connexes