Set any one of the delegate method is #required - iphone

I am having a protocol in which I have two methods as follows.
#protocol ActionPerformerDelegate <NSObject>
#required
- (void)actionCompleted;
- (void)actionCompletedWithMessage:(NSString *)message;
#end
If a class confirms to this protocol, that class should implement at least one of these methods. I know about #required and #optional keywords. If I use #required, Xcode warns me to implement both the methods. If I use #optional Xcode doesn't warn me to implement any of the methods. How to specify that implementing any one of the methods alone is necessary?

Protocol methods are either required or optional; what you're asking for cannot be checked at compile time. You could however mark both methods as optional and check which your delegate implements at runtime. Something similar to the following:
// In ActionPerformer.m.
SEL selector = #selector(actionCompletedWithMessage:);
if ([self.delegate respondsToSelector:selector]) {
// ...
} else if ([[self.delegate class] respondsToSelector:selector]) {
// ...
} else {
[NSException raise:NSInvalidArgumentException format:#"delegate doesn't "
"implement actionCompletedWithMessage:."];
}

Related

If a controller conforms to a protocol then is it necessary for it to provide a body to all the methods of protocol?

In Java, there is wrapper classes. but in objective c what is there any wrapper class or something else?
In ObjectiveC protocol methods can be marked as #optional - those ones don't have to be implemented. e.g.
#protocol MyProtocol <NSObject>
#required
- (NSUInteger) methodOne;
#optional
- (NSUInteger) methodTwo; // Doesn't have to be implemented
#end
The method that calls the protocol should then check to see if the instance responds to that selector:
if ([anInstanceOfAClassThatImplementsMyProtocol respondsToSelector:#selector( )]) {
[myProtocolInstance methodTwo];
}
You wil get a warning if you dont implement obligatory methods in the protocol. A protocol is typically defined like this:
#protocol SomeProtocol<NSObject>
- (void)obligatoryMethod;
#optional
- (void)optionalMethod;
#end

First time using Protocols - Objective-C

This is my first time using Protocols in Objective-C, and I'm running into a trouble: Here's what I've got:
I have a ReportsReceiver.h:
#protocol ReportsReceiver
-(void)receiveData:(NSArray *)theData;
#end
I have a MyController.h:
#interface MyController : UIViewController<ReportsReceiver,UITableViewDelegate,UITableViewDataSource> {
}
#end
I have a MyController.m with the implemented method:
- (void)receiveData:(NSArray *)theData {
NSLog(#"received some data!");
}
And then I have a class AllUtilities.m with the declaration:
Protocol *receiverProtocol;
AllUtilities.m also contains a method to initialize the protocol:
- (void)initProtocol {
receiverProtocol = #protocol(ReportsReceiver);
}
And then later on in AllUtilities.m I make the call:
[receiverProtocol receiveData:anArray];
Which crashes the application with the error:
2011-01-07 11:46:27.503 TestGA[91156:207] *** NSInvocation: warning: object 0x9c28c of class 'Protocol' does not implement methodSignatureForSelector: -- trouble ahead
2011-01-07 11:46:27.504 TestGA[91156:207] *** NSInvocation: warning: object 0x9c28c of class 'Protocol' does not implement doesNotRecognizeSelector: -- abort
How can I fix this? Thanks!!
You should read the part about protocols in the Objective-C guide once more :) I think you don’t really understand how protocols work. This is what you want:
// DataProducer.h
#protocol DataConsumer
- (void) handleData: (NSArray*) data;
#end
#interface DataProducer
#end
// DataProducer.m
#implementation DataProducer
- (void) generateDataAndPassTo: (id <DataConsumer>) consumer
{
NSArray *data = …;
[consumer handleData:data];
}
// SomeController.h
#import "DataProducer.h"
#interface SomeController <DataConsumer>
#end
// SomeController.m
#implementation SomeController
- (void) requestData
{
// The producer is of type DataProducer.
// Where you get it is irrelevant here.
[producer generateDataAndPassTo:self];
}
- (void) handleData: (NSArray*) data
{
NSLog(#"Got data.");
}
#end
A protocol is, in essence, a contract that says, for example, "an object conforming to the ReportsReceiver protocol must implement the receiveData: method".
So, MyController.h promises that receiveData: will be present, and MyController.m fulfills the promise. So far so good.
Now, your receiver variable doesn't care exactly what type of object the receiver is, so long as it conforms to the ReportsReceiver protocol. The way you declare that is:
id<ReportsReceiver> receiver;
...and in your initialization you might say:
receiver = myController;
Then invoke it like:
[receiver receiveData:anArray];
Start with adding the NSObject protocol to your own protocol. The warnings you are getting are methods from NSObject.
#protocol ReportsReceiver <NSObject>
-(void)receiveData:(NSArray *)theData;
#end
When declaring an object that implements a protocol, it should be more like:
id<ReportsReceiver> receiverProtocol;
or
ReceiverClass<ReportsReceiver> *receiverProtocol;
in the case that you create an object (ReceiverClass) that implements the ReportsReceiver protocol.
You assign a class that implements a protocol in the same way you assign any other class:
ReceiverClass<ReportsReceiver> *receiverProtocol;
- (void)initProtocol {
receiverProtocol = [[ReceiverClass alloc]init];
}
The #protocol directive begins declaring a protocol, not casting to one. Check out the docs for how to use them.

iPhone - how do I know if a protocol method was implemented?

I have created a class and this class has its own delegate protocol.
Inside that protocol, there's an optional method, declared like
#protocol myClassDelegate <NSObject>
#optional
- (void) myOptionalMethod;
#end
Inside the class I have a call to myOptionalMethod, in the form of
[delegate myOptionalMethod];
but as the method is optional, if I call this method on a delegate that has not implemented the method, it will crash.
So, how do I test to see if the method was implemented before calling it?
thanks.
This is pretty easy.
if([delegate respondsToSelector:myOptionalMethod]){
// You can now call this method without a crash
[delegate myOptionalMethod];
}
-respondsToSelector: is useful for individual methods, as others have posted here. For a stricter interpretation, you can see whether a class was declared as implementing a protocol with the -conformsToProtocol: method:
BOOL isAGrommet = [myObject conformsToProtocol: #protocol(Grommet)];
You should use the respondsToSelector method to determine if the delegate has the relevant method prior to calling the selector on the delegate.
For example:
if([delegate respondsToSelector:#selector(myOptionalMethod)]) {
[delegate myOptionalMethod];
}

How to implement delegation the right way?

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?
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
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
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.

How to create a protocol with methods that are optional?

I noticed methods marked optional in several protocols defined in the iPhone SDK, such as the UIActionSheetDelegate protocol for example.
How can I define a protocol of my own, and set a few of the methods as optional?
From the Apple page on "Formal Protocols":
Optional Protocol
methods can be marked as optional
using the #optional keyword.
Corresponding to the #optional modal
keyword, there is a #required keyword
to formally denote the semantics of
the default behavior. You can use
#optional and #required to partition
your protocol into sections as you see
fit. If you do not specify any
keyword, the default is #required.
#protocol MyProtocol
- (void)requiredMethod;
#optional
- (void)anOptionalMethod;
- (void)anotherOptionalMethod;
#required
- (void)anotherRequiredMethod;
#end
If a method in a protocol is marked as optional, you must check whether an object implements that method before attempting to call it.
As an example, the pie chart view might test for the segment title method like this:
NSString *thisSegmentTitle;
if ([self.dataSource respondsToSelector:#selector(titleForSegmentAtIndex:)]) {
thisSegmentTitle = [self.dataSource titleForSegmentAtIndex:index];
}
The respondsToSelector: method uses a selector, which refers to the identifier for a method after compilation. You can provide the correct identifier by using the #selector() directive and specifying the name of the method.
If the data source in this example implements the method, the title is used; otherwise, the title remains nil.
Protocols is set of rules. We can create protocols as below example:
TestProtocols.h
#protocol TestProtocols <NSObject>
#optional
-(void)testMethodOptional;
#required // by default
-(void)testMethodRequired;
#end
Implementation:
TestClass.h
#import "TestProtocols.h"
#interface TestClass : NSObject <TestProtocols>
#end
TestClass.m
#import "TestClass.h"
#implemenation TestClass
//optional to implement
-(void)testMethodOptional{
// Your Code
}
//required to implement
-(void)testMethodRequired{
// Your Code
}
#end
Use the #optional keyword before your method declaration to make it optional. Simple as that!
// myProtocol.h
#protocol myProtocol
- (void)myMandatoryMethod:(id)someArgument;
#optional
- (void)myOptionalMethod:(id)someArgument;
#end
// myClass.m
#interface myClass : someSuperClass <myProtocol>
//...
#end
Protocols act the same as abstract classes, so the #optional keyword defines those methods that are optional for implementation.
So, in the code, someMethod1, someMethod2 and someMethod4 are required methods (must be implemented). someMethod3 is optional - if we didn't implement this method, the compiler will not throw any warnings.
#protocol myPrtocol<NSObject>
-(void)someMethod1:(id)someArgument;
-(void)someMethod2:(id)someArugument;
#optional
-(void)someMethod3:(id)someArgument;
#required //by default
-(void)someMethod4:(id)someArgument;
#end
// sampleClass.m
#interface sampleClass : someSuperClass <myProtocol>
//...
#end