views:

402

answers:

2

I want to subclass UITextView, and send a new message to the delegate. So, I want to extend the delegate protocol, What's the correct way to do this?

I started out with this:

interface:

#import <Foundation/Foundation.h>

@class MySubClass;

@protocol MySubClassDelegate <UITextViewDelegate>
- (void) MySubClassMessage: (MySubClass *) subclass;
@end


@interface MySubClass : UITextView {
}

@end

implementation:

#import "MySubClass.h"


@implementation MySubClass

- (void) SomeMethod; { 
    if ([self.delegate respondsToSelector: @selector (MySubClassMessage:)]) { 
        [self.delegate MySubClassMessage: self];
    }
}

@end

however with that I get the warning: '-MySubClassMessage:' not found in protocol(s).

I had one way working where I created my own ivar to store the delegate, then also stored the delegate using [super setDelegate] but that seemed wrong. perhaps it's not.

I know I can just pass id's around and get by, but My goal is to make sure that the compiler checks that any delegate supplied to MySubClass conforms to MySubClassDelegate protocol.

To further clairfy:

@interface MySubClassTester : NSObject {

}

@implementation MySubClassTester

- (void) one { 
    MySubClass *subclass = [[MySubClass alloc] init];
    subclass.delegate = self;
}

@end

will produce the warning: class 'MySubClassTester' does not implement the 'UITextViewDelegate' protocol

I want it to produce the warning about not implementing 'MySubClassDelegate' protocol instead.

Thanks, a bunch. (thanks brad)

A: 

Given that MySubClassMessage: is optional, you should be able to simple do a simple:

- (void) SomeMethod { 
  SEL delegateSelector = @selector(MySubClassMessage:);
  if ([self.delegate respondsToSelector:delegateSelector]) { 
    [self.delegate performSelector:delegateSelector withObject:self];
  }
}

The complier should still check that the implementing class conforms to your protocol (or at least claim to in the header) and you won't get the error you described.

Brad Smith
Given that it's optional, wouldn't this crash if the delegate doesn't implement the method?
Chuck
@chuck, by itself, yes. So you should first check that [self.delegate respondsToSelector: @selector (MySubClassMessage:)] evaluates to true. I'll edit my answer to have the full method
Brad Smith
there's a good point. since my example says @optional it doesn't really matter if the object is conforming. I'm really interested in if it's not optional. I'll take that out of the example. If I understand this correctly, isn't performSelector just avoiding the protocol conformance check here. Wouldn't it still be possible to assign a non conforming delegate since the delegate accessors are actually defined in UITextViews super class?
fess .
+2  A: 

The UITextView defines its delegate as

@property(nonatomic, assign) id<UITextViewDelegate> delegate

meaning it conforms to UITextViewDelegate, and that's what compiler checks. If you want to use the new protocol, you need to redefine delegate to conform to your protocol:

@interface MySubClass : UITextView {
}
@property(nonatomic, assign) id<MySubClassDelegate> delegate   
@end

The compiler shouldn't give any more warnings.

[Update by fess]

... With this the compiler will warn that the accessors need to be implemented... [I implemented this:]

-(void) setDelegate:(id<MySubClassDelegate>) delegate {
[super setDelegate: delegate];
}
- (id) delegate {
return [super delegate];
}

"

[My update]

I believe it should work if you only make a @dynamic declaration instead of reimplementing the method, as the implementation is already there:

@dynamic delegate;
Mo
thanks. With this the compiler will warn that the accessors need to be implemented. though they are there in the superclass. I previously failed to implement these, and that drove me to storing the delegate in my own ivar. however I've tried again given you recommendation, and that did it. can you add these too your answer so they get formatted nicely: `- (void) setDelegate:(id<MySubClassDelegate>) delegate { [super setDelegate: delegate];}- (id) delegate { return [super delegate];}`
fess .
@dynamic delegate. does work. thanks a bunch, I understand things much better now.
fess .