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
Related
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
I'm arranging my methods into groups using #pragma mark in implementation. But sometimes, the method implementation code appears below the code that calls this method, and I'm getting "Instance method not found" warnings. It happens when I'm using private methods. How to fix that?
Simplest method is to use a anonymous category. Add something like this to the top of your .m file, before your #implementation:
#interface MyClass()
- (void)myPrivateMethod;
#end
In your Class.m implementation file, you can add an interface section at the beginning and declare private functions in there:
#interface YourClassName (private)
-(void)aPrivateMethod:(NSString*)aParameter;
...
#end
#implementation YourClassName
...
#end
In this case, you would use a class extension inside of your implementation file to define these methods. In this manner, your 'public' API is still defined in your header file, and your implementation file contains the definition of your pseudo-private methods.
YourClass.m
#interface MyClass()
- (void)myPrivateMethod;
#end
#implementation MyClass
- (void)myPublicMethod
{
// This will not throw an error or warning
[self myPrivateMethod];
}
- (void)myPrivateMethod
{
// Do something
}
#end
(I found some questions discussing the idea, but I didn't see a solution for my problem.)
I added this convenience method as a category to NSObject. (I've added other methods, so I'm still interested in an answer even if you disagree with this particular convenience method.)
#implementation NSObject (MyCategory)
- (void)performInvocationOnMainThread:(NSInvocation *)invocation waitUntilDone:(BOOL)waitForMainThread;
#end
Then I have a protocol I defined:
#protocol MyDelegateProtocol <NSObject>
- (void)myDelegateProtocolMethod;
#end
Then I declare the delegate as a property of my class that implements said protocol.
#property (nonatomic, assign) id <MyDelegateProtocol> delegate;
But when I try to call the NSObject method I added in my category like so
NSInvocation *invocation = [self.delegate invocationForSelector:#selector(someSelector:withArg:)];
I get this warning
'-performInvocationOnMainThread:waitUntilDone:' not found in protocol(s)
If I cast my delegate as (NSObject *) then I don't get the warning. What am I doing wrong? It didn't seem like I could (or should?) add methods to an existing protocol without creating a "sub protocol" and using it from then on. (Which kind of defeats the point of adding methods to NSObject in mind.)
NSInvocation *invocation = [(NSObject *)self.delegate invocationForSelector:#selector(someSelector:withArg:)];
Your category extends the NSObject class, not the NSObject protocol. While the class now has the method, it's not defined as part of the protocol, hence the warning.
That's why typecasting to the NSObject * pointer type works; you're casting to the NSObject class type, rather than something like id<NSObject> which means an arbitrary Objective-C object that conforms to the NSObject protocol.
You'll have to make an intermediate protocol (or "sub protocol") that extends the NSObject protocol:
#protocol ExtendedNSObject <NSObject>
- (void)performInvocationOnMainThread:(NSInvocation *)invocation waitUntilDone:(BOOL)waitForMainThread;
#end
Then have your delegate protocol extend that one instead:
#protocol MyDelegateProtocol <ExtendedNSObject>
- (void)myDelegateProtocolMethod;
#end
If I'm not wrong, you can keep the existing NSObject (MyCategory) implementation, and they'll play nice together.
when pass/expect this type, qualify it like so:
- (void)race:(NSObject<MyDelegateProtocol>*)arg;
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:."];
}
I have a large class, which I have divided into several different class extension files for readability.
#protocol MyProtocol
#required
-(void)required;
#end
#interface MyClass : NSObject <MyProtocol>
#end
#interface MyClass (RequiredExtension)
-(void)required;
#end
Is there a better way to do this, without the compiler warning?
warning: class 'MyClass' does not fully implement the 'MyProtocol' protocol
Use a category for each protocol implementation. I use this when I have complex viewControllers.
For example, I have a category that implements NSTextDelegate protocol.
So, MyComplexViewController+NSTextDelegate.h:
#import "MyComplexViewController.h"
#interface MyComplexViewController (NSTextDelegate) <NSTextDelegate>
#end
and MyComplexViewController+NSTextDelegate.m:
#import "MyComplexViewController+NSTextDelegate.h"
#implementation MyComplexViewController (NSTextDelegate)
- (BOOL)textShouldBeginEditing:(NSText *)textObject{
...
}
- (BOOL)textShouldEndEditing:(NSText *)textObject{
...
}
- (void)textDidBeginEditing:(NSNotification *)notification{
...
}
- (void)textDidEndEditing:(NSNotification *)notification{
...
}
- (void)textDidChange:(NSNotification *)notification{
....
}
#end
Then I take all the headers for the main class definition and the categories and combine them into one header which I then import where I need to use the class.
#interface MyClass : NSObject
#end
#interface MyClass (RequiredExtension) <MyProtocol>
-(void)required;
#end
Adopt the protocol in the category.
You don't need to change your style of coding. To get around the warning, it only need to implement "required" method of the protocol, not "optional"
If that's only for readability, you should use categories only. A protocol is not needed in such a case.