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:
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 "