Avoid compiler warnings when forwarding messages

I created a class that wraps a UITextView and adds some ui elements. I want the new class API to be identical with the UITextView, so I use message forwarding (the list below) to send messages between the wrapped text view and the delegate.

It is annoying that the compiler generates warnings for method calls on instances of my redirect class. For example, an error will be generated for the following line:

[aMyTextView setContentOffset:CGPointZero animated:YES]; 

Therefore, I have to declare and create a โ€œmanual redirectโ€ for these methods, which is detrimental to the whole purpose of using message forwarding.

 - (void)setContentOffset:(CGPoint)contentOffset animated:(BOOL)animated { [_textView setContentOffset:contentOffset animated:animated]; } 

I know that the usual way around this is to use one of the performSelector: methods, but it is a) cumbersome when some arguments are not NSObjects (although Erica Sadun extensions are a big help), b) again, completely contradicts the intention to create a transparent shell.

(Subclassing UITextView is also out of the question, because I need to insert the views under the text view.)

Is there any way around this?

List of all relevant parts of the class:

 @interface MyTextField : UIView<UITextViewDelegate> { UIImageView* _border; UITextView* _textView; UIButton* _clearButton; NSObject<UITextViewDelegate>* _delegate; } @implementation MWTextField . . . // Forwards messages in both directions (textView <--> delegate) #pragma mark Message forwarding // Protocol messages will only be sent if respondsToSelector: returns YES - (BOOL)respondsToSelector:(SEL)aSelector { if ([_delegate respondsToSelector:aSelector]) return YES; else return [super respondsToSelector:aSelector]; } - (NSMethodSignature *)methodSignatureForSelector:(SEL)selector { // First, try to find it in the UITextView if ([_textView respondsToSelector:selector]) { return [_textView methodSignatureForSelector:selector]; } // Then try the delegate else if ([_delegate respondsToSelector:selector]) { return [_delegate methodSignatureForSelector:selector]; } else { return [super methodSignatureForSelector: selector]; } } - (void)forwardInvocation:(NSInvocation *)invocation { SEL aSelector = [invocation selector]; if ([_textView respondsToSelector:aSelector]) { [invocation invokeWithTarget:_textView]; } else if ([_delegate respondsToSelector:aSelector]) { [invocation invokeWithTarget:_delegate]; } else { [self doesNotRecognizeSelector:aSelector]; } } . . . @end 
+4
source share
2 answers

Declare a category that provides method method declarations that you forward:

 @interface MyTextField (ImGonnaLetYouFinishButFirstImForwardingThese) ... methods you want to forward here ... @end 

No need to provide @implementation.

Please note that this is a rather atypical template. Not really, really. There should be no reason why you cannot subclass. You say that Subclassing UITextView is out of the question, too, because I need to insert views under the text view, but that is not the case.


If I subclass UITextField, all I can do with other views is add them as subitems, which means they will be on top of the text field. I think I can change drawRect: ... is that what you would suggest? Or what do you have up there?

If you need a group, create a subclass of UIView that manages the various subviews accordingly, without the need for forwarding. You can then arrange the views as you like.

The expedition is used extremely rarely. Down this path is insanity. It really seems like your design is a little weedy, but the information is not enough to really say anything more specific.

+4
source

A simple solution is to use dynamic typing and declare aMyTextView as id , the warnings go away.

0
source

Source: https://habr.com/ru/post/1301214/


All Articles