Mixins ou hérédité multiple en Objective-C?

Disons par exemple que j'ai MyUITextViewSubclass qui hérite de UITextView et MyUITextFieldSubclass qui hérite de UITextField et ces deux sous-classs contiennent beaucoup des mêmes methods et propriétés pour append un comportement similaire à ces controls d'interface user.

Puisque UITextView et UITextField héritent de classs différentes, existe-t-il un moyen facile de créer une class abstraite pour combiner tout ce code répété? En d'autres termes, est-il possible de créer une class abstraite dont je pourrais hériter pour ces deux sous-classs et de simplement replace les methods qui sont différentes entre les deux?

Ce que je sais jusqu'ici:

  • Je sais que Objective-C ne supporte pas l'inheritance multiple (inheritance de deux classs ou plus)
  • Je sais que je pourrais append des methods communes en utilisant les Catégories, mais je ne pense pas que cela résout les methods d'initialisation ou l'ajout de propriétés privées.

En s'appuyant sur la réponse d'Amin, voici comment vous pourriez le faire:

Étape 1: Créez un protocole TextSurrogateHosting qui contiendra toutes les methods de vos sous-classs UITextField et UITextView auxquelles vous devez accéder à partir des methods que vous souhaitez append aux deux sous-classs. Cela peut être par exemple une méthode text et setText: afin que vos methods puissent accéder et définir le text d'un champ de text ou d'une vue de text. Cela pourrait ressembler à ceci:

SPWKTextSurrogateHosting.h

 #import <Foundation/Foundation.h> @protocol SPWKTextSurrogateHosting <NSObject> - (NSSsortingng *)text; - (void)setText:(NSSsortingng *)text; @end 

Étape 2: Créez une class TextSurrogate qui contient toutes les methods que vous souhaitez partager entre les sous-classs UITextField et UITextView . Ajoutez ces methods à un protocole afin que nous puissions utiliser l'achèvement du code dans Xcode et éviter les avertissements / erreurs du compilateur.

SPWKTextSurrogate.h

 #import <Foundation/Foundation.h> #import "SPWKTextSurrogateHosting.h" @protocol SPWKTextSurrogating <NSObject> @optional - (void)appendQuestionMark; - (void)appendWord:(NSSsortingng *)aWord; - (NSInteger)characterCount; - (void)capitalize; @end @interface SPWKTextSurrogate : NSObject <SPWKTextSurrogating> /* We need to init with a "host", either a UITextField or UITextView subclass */ - (id)initWithHost:(id<SPWKTextSurrogateHosting>)aHost; @end 

SPWKTextSurrogate.m

 #import "SPWKTextSurrogate.h" @implementation SPWKTextSurrogate { id<SPWKTextSurrogateHosting> _host; } - (id)initWithHost:(id<SPWKTextSurrogateHosting>)aHost { self = [super init]; if (self) { _host = aHost; } return self; } - (void)appendQuestionMark { _host.text = [_host.text ssortingngByAppendingSsortingng:@"?"]; } - (void)appendWord:(NSSsortingng *)aWord { _host.text = [NSSsortingng ssortingngWithFormat:@"%@ %@", _host.text, aWord]; } - (NSInteger)characterCount { return [_host.text length]; } - (void)capitalize { _host.text = [_host.text capitalizedSsortingng]; } @end 

Étape 3: Créez votre sous-class UITextField . Il contiendra trois methods standard requirejses pour transmettre des invocations de methods non reconnues à votre SPWKTextSurrogate .

SPWKTextField.h

 #import <UIKit/UIKit.h> #import "SPWKTextSurrogateHosting.h" #import "SPWKTextSurrogate.h" @interface SPWKTextField : UITextField <SPWKTextSurrogateHosting, SPWKTextSurrogating> @end 

SPWKTextField.m

 #import "SPWKTextField.h" @implementation SPWKTextField { SPWKTextSurrogate *_surrogate; } - (id)initWithFrame:(CGRect)frame { self = [super initWithFrame:frame]; if (self) { _surrogate = [[SPWKTextSurrogate alloc] initWithHost:self]; } return self; } #pragma mark Invocation Forwarding - (void)forwardInvocation:(NSInvocation *)anInvocation { if ([_surrogate respondsToSelector:[anInvocation selector]]) { [anInvocation invokeWithTarget:_surrogate]; } else { [super forwardInvocation:anInvocation]; } } - (NSMethodSignature*)methodSignatureForSelector:(SEL)selector { NSMethodSignature* signature = [super methodSignatureForSelector:selector]; if (!signature) { signature = [_surrogate methodSignatureForSelector:selector]; } return signature; } - (BOOL)respondsToSelector:(SEL)aSelector { if ([super respondsToSelector:aSelector] || [_surrogate respondsToSelector:aSelector]) { return YES; } return NO; } @end 

Étape 4: Créez votre sous-class UITextView .

SPWKTextView.h

 #import <UIKit/UIKit.h> #import "SPWKTextSurrogateHosting.h" #import "SPWKTextSurrogate.h" @interface SPWKTextView : UITextView <SPWKTextSurrogateHosting, SPWKTextSurrogating> @end 

SPWKTextView.m

 #import "SPWKTextView.h" #import "SPWKTextSurrogate.h" @implementation SPWKTextView { SPWKTextSurrogate *_surrogate; } - (id)initWithFrame:(CGRect)frame { self = [super initWithFrame:frame]; if (self) { _surrogate = [[SPWKTextSurrogate alloc] initWithHost:self]; } return self; } #pragma mark Invocation Forwarding - (void)forwardInvocation:(NSInvocation *)anInvocation { if ([_surrogate respondsToSelector:[anInvocation selector]]) { [anInvocation invokeWithTarget:_surrogate]; } else { [super forwardInvocation:anInvocation]; } } - (NSMethodSignature*)methodSignatureForSelector:(SEL)selector { NSMethodSignature* signature = [super methodSignatureForSelector:selector]; if (!signature) { signature = [_surrogate methodSignatureForSelector:selector]; } return signature; } - (BOOL)respondsToSelector:(SEL)aSelector { if ([super respondsToSelector:aSelector] || [_surrogate respondsToSelector:aSelector]) { return YES; } return NO; } @end 

Étape 5: Utilisez-le:

 SPWKTextField *textField = [[SPWKTextField alloc] initWithFrame:CGRectZero]; SPWKTextView *textView = [[SPWKTextView alloc] initWithFrame:CGRectZero]; textField.text = @"The green fields"; textView.text = @"What a wonderful view"; [textField capitalize]; [textField appendWord:@"are"]; [textField appendWord:@"green"]; [textField appendQuestionMark]; NSLog(@"textField.text: %@", textField.text); // Output: The Green Fields are green? [textView capitalize]; [textView appendWord:@"this"]; [textView appendWord:@"is"]; NSLog(@"textView.text: %@", textView.text); // Output: What A Wonderful View this is 

Ce model devrait résoudre votre problème. J'espère que 🙂

D'autres informations générales sont disponibles ici: https://developer.apple.com/library/mac/documentation/Cocoa/Conceptual/ObjCRuntimeGuide/Articles/ocrtForwarding.html#//apple_ref/doc/uid/TP40008048-CH105

Ce que tu veux, c'est un mixin. Cela n'est pas pris en charge dans Objective-C. Les catégories ne sont pas mixes, car elles ajoutent une API à une class pas à beaucoup (> 1) de classs. En utilisant des catégories, ce qui n'est pas possible pour plusieurs raisons, comme vous l'avez dit, ne vous aiderait pas.

La façon habituelle de résoudre ce problème consiste à créer une class d'assistance contenant le code supplémentaire et à l'utiliser dans les deux classs.

Ensuite, vous vous refindez à taper

 [myUITextViewSubclass.helper doSomething] 

au lieu de

 [myUITextViewSubclass doSomething] 

Si c'est vraiment un problème, vous pouvez le résoudre avec des invocations directes. Écris juste un commentaire.

Non ce n'est pas possible.

La chose la plus proche que vous pourriez réaliser serait d'append manuellement des fonctionnalités à UITextView pour le faire imiter UITextField . L'inconvénient évident est que vous devez le faire tous manuellement, avec votre propre code.

Vous pouvez utiliser une macro de préprocesseur, mais elle est sujette aux erreurs.

Les traits ou Mixins ne sont pas supportés par Objective-C, vous avez seulement l'option embeddede de Catégories. Mais heureusement, Objective-C Runtime a presque tous les outils pour implémenter sa propre idée si le mélange ou les traits avec l'ajout de methods et de propriétés à votre class au moment de l'exécution. Vous pouvez en savoir plus sur les opportunités offertes par Objective-C Runtime sur le site Web de documentation d' Objective-C Runtime Docs

L'idée est:

1) Vous pouvez créer un protocole Objective-C (Mixin), dans lequel vous déclarerez des propriétés et des methods.

2) Ensuite, vous créez une class (implémentation Mixin), qui implémentera les methods de ce protocole.

3) Vous faites votre class, dans laquelle vous voulez fournir la possibilité de composition avec des mixins, pour vous conformer à ce protocole (Mixin).

4) Lorsque votre application se lance, vous ajoutez à l'exécution d'Objective-C toutes les implémentations de la class (implémentation Mixin) et les propriétés déclarées dans (Mixin) dans votre class.

5) voilà 🙂

Ou vous pouvez utiliser des projets open source prêts comme " Alchemiq "