Reputation:
I'm trying to implement delegation for a class which should call it's delegate (if any), when special things happen.
From Wikipedia I have this code example:
@implementation TCScrollView
-(void)scrollToPoint:(NSPoint)to;
{
BOOL shouldScroll = YES;
// If we have a delegate, and that delegate indeed does implement our delegate method,
if(delegate && [delegate respondsToSelector:@selector(scrollView:shouldScrollToPoint:)])
shouldScroll = [delegate scrollView:self shouldScrollToPoint:to]; // ask it if it's okay to scroll to this point.
if(!shouldScroll) return; // If not, ignore the scroll request.
/// Scrolling code omitted.
}
@end
If I try this on my own, I get a warning that the method I am calling on the delegate was not found. Of course it was not, because the delegate is just referenced by id. It could be anything. Sure at runtime that will work fine because I check if it responds to selector. But I don't want the warning in Xcode. Are there better patterns?
Upvotes: 1
Views: 961
Reputation: 5554
You could let the delegate be of the id type that implements the SomeClassDelegate protocol. For this, you could in the header of your SomeClass (in your case TCScrollView), do something like this:
@protocol TCScrollViewDelegate; // forward declaration of the protocol
@interface TCScrollView {
// ...
id <TCScrollViewDelegate> delegate;
}
@property (assign) id<TCScrollViewDelegate> delegate;
@end
@protocol TCScrollViewDelegate
- (BOOL) scrollView:(TCScrollView *)tcScrollView shouldScrollToPoint:(CGPoint)to;
@end
Then you can from your implementation, just call the method on the delegate:
@implementation TCScrollView
-(void)scrollToPoint:(NSPoint)to;
{
BOOL shouldScroll = YES;
shouldScroll = [delegate scrollView:self shouldScrollToPoint:to]; // ask it if it's okay to scroll to this point.
if(!shouldScroll) return; // If not, ignore the scroll request.
/// Scrolling code omitted.
}
@end
Upvotes: 7
Reputation: 45551
Use [NSObject performSelector:]
[delegate performSelector:@selector(scrollView:shouldScrollToPoint:) withObject:self withObject:to];
You won't get the compiler warnings anymore.
Alternatively create a prototcol and declare MyProtocol *delegate
in header file.
Upvotes: 0
Reputation: 135548
Following up on the sample code in drvdijk's answer, there could be a problem if there is any chance that delegate
could be nil
when you call the delegate method.
The return value of a message sent to nil
is nil
(aka 0.0
aka 0
aka NO
), so if delegate
is nil
,
[delegate scrollView:self shouldScrollToPoint:to]
will return NO
, which might not be the desired behavior in your case. It's safer to check first:
if (delegate != nil) {
shouldScroll = [delegate scrollView:self shouldScrollToPoint:to]
}
Also, if you don't want to see a compiler warning when sending messages declared by NSObject
to your delegate (such as respondsToSelector:
), include the NSObject
protocol in your protocol declaration:
@protocol TScrollViewDelegate <NSObject>
- (BOOL) scrollView:(TCScrollView *)tcScrollView shouldScrollToPoint:(CGPoint)to;
@end
Upvotes: 0