Pass a protocol as a method argument - objective-c

First let me explain what I don't mean. I don't want to type an argument to a protocol:
-(void)someMethod:(id<SomeProtocol>)someArgument;
What I do want to is to pass a protocol to a method in the same way I can pass a Class to a method (The following is incorrect, but it hopefully explains what I want to do):
-(void)someMethod:(Protocol)someArgument;
I would then like to be able to use the Protocol to check whether a set of objects implement it.

If you know the name of a protocol at coding-time, use #protocol(SomeProtocol) to get a pointer to that protocol, similar to how you'd use #selector(x).
Beyond that, you just refer to protocols with the class identifier Protocol -- so you're method declaration would look like:
-(void)someMethod:(Protocol*)someArgument
You can see an example in the docs for NSObject conformsToProtocol:
http://developer.apple.com/library/mac/#documentation/Cocoa/Reference/Foundation/Classes/NSObject_Class/Reference/Reference.html#//apple_ref/occ/clm/NSObject/conformsToProtocol:

Protocol is a class, so you just write - (void)someMethod:(Protocol *)someArgument like with any other object type. You can see this in the declaration for conformsToProtocol::
+ (BOOL)conformsToProtocol:(Protocol *)aProtocol

- (void) executeRequest:(id<Protocol1>)request andCompletion:(id<Protocol2>)response
the only way to pass protocol into an argument
because id<..> means it needs to conform to that protocol before pass throw the argument

I don't recommend using protocol. It will obscure which interface your code actually relies on. Use id<yourprotocol>*. This is actually how the cocoa frameworks pass protocols. Forgive the use of words if I don't it thinks I'm trying to do HTML.

Related

objective c init in protocol

yesterday a colleague asked, why we should not declare an init method (initWith...:(...)) in a protocol to force implementing classes to supply such an initializer. I was quite suprised about that question and in my understanding, this is nonsense. But I could not find a definitive reason but that declaring an init method in a protocol leads to less flexibility for the implementations.
Could you please tell me a good reason, why there should or should not be an init method in a protocol?
Thanks!
You define methods in protocols so that your code could call methods implemented by others. The "contract" between you and developers implementing your protocol looks like this:
You define the protocol,
Someone else implements your protocol,
Someone else creates an object implementing your protocol, and gives it to you, so
You can call methods of your protocol without knowing their implementation.
In order to call methods of your protocol, you need to have an instance of an object implementing it. The whole point of defining protocols is removing from your code any knowledge about the class implementing your protocol: if you know which class you are going to get, you might as well skip the protocol, and program to the class directly. However, if you want to call your init, you have to either know the class, or someone else must pass you an alloc-ed object on which the init has not been called yet. Neither alternative is a good idea - the first one kills the purpose of having protocols, and the second forces your callers deal in partially initialized objects.
Note that it does not prevent you from having non-init configuration methods in a protocol: if all objects must be configured using certain bits of information, let your users implement whatever init that they want, and add a configureWith:... method to your protocol, letting you control the process of configuring the object without knowing about its init method.
I know some protocols in iOS SDK which has init... methods. For example NSCoding Protocol has – initWithCoder: required method. I think it is normal practice.

Protocol on method declaration?

I'm starting to use the Nimbus framework and I just ran across this syntax for the first time. It looks like they are using some kind of protocol in the method declaration and then when declaring a variable. I've only seen protocols used in the header file right after the class name so this is completely new to me.
- (UIView<NIPagingScrollViewPage>*)pagingScrollView:(NIPagingScrollView *)pagingScrollView pageViewForIndex:(NSInteger)pageIndex {
Also:
UIView<NIPagingScrollViewPage>* pageView = nil;
What exactly does this mean? Why are they using this format?
That declaration makes sure that the UIView returned conforms to the NIPagingScrollViewPage protocol. The compiler will emit a warning if the method tries to return an object that isn't declared to conform.
A more common usage of that syntax would be a delegate, as you'll allow any class that conforms to the protocol to be the delegate, so that syntax is used to make sure the class conforms to the protocol.
-(void)setDelegate:(id<SampleDelegate>)del //Makes sure that del conforms to the protocol SampleDelegate, the compiler will emit a warning
This is just the way to declare that it is confirming to that protocol. Otherwise warnings will be shown. Then you have to use id.
So It is always a good practice to use (datatype<protocol>*)variableName

objc_getProtocol() returns NULL for `NSApplicationDelegate"?

I'm trying to use the objc_getProtocol() function to get a reference to the struct representing the NSApplicationDelegate protocol:
Protocol *protocol = objc_getProtocol("NSApplicationDelegate");
However, for some reason, this always returns NULL.
Other protocols such as NSObject, NSCoding, NSTableViewDelegate, and NSTableViewDataSource work fine.
Is there something special about NSApplicationDelegate, or am I doing something wrong?
Found the answer in the Apple docs:
http://developer.apple.com/library/ios/#DOCUMENTATION/Cocoa/Conceptual/ObjectiveC/Chapters/ocProtocols.html#//apple_ref/doc/uid/TP30001163-CH15
The compiler creates a protocol object for each protocol declaration it encounters, but only if the protocol is also:
Adopted by a class,
Or referred to somewhere in source code (using
#protocol())

Introspect parameter of type: id to decide whether it is a class or a protocol

I have the following method:
-(void)SomeMethod:(id)classOrProtocol;
It will be called like this:
[self someMethod:#protocol(SomeProtocol)];
Or
[self someMethod:[SomeClass class]];
Within the method body I need to decide if |classOrProtocol| is:
Any Class(Class) OR Any Protocol(Protocol) OR Anything else
[[classOrProtocol class] isKindOfClass: [Protocol class]]
Results in a (build)error:
Receiver 'Protocol' is a forward class and corresponding #interface may not exist
So how can I tell a Protocol from a Class from anything else?
In Objective-C 2 (i.e. unless you use 32 bit runtime on OS X) Protocol is defined to be just a forward class, see /usr/include/objc/runtime.h. The real interface is nowhere declared. You can try to include /usr/inlcude/objc/Protocol.h by saying
#import <objc/Protocol.h>
but as is written there, no method is publicly supported for an instance of Protocol. The only accepted way to deal with Protocol instances is to use runtime functions, given in Objective-C Runtime Reference. It's not even publicly defined whether Protocol is a subclass of anything, and it's not even stated that it implements NSObject protocol. So you can't call any method on it.
Of course you can use the source code of the runtime to see what's going on. Protocol inherits from Object (which is a remnant from pre-OpenStep NeXTSTep), not from NSObject. So you can't use the familiar methods for NSObject-derived objects, including Class of NSObject-derived objects. See the opensourced implementations of Protocol.h and Protocol.m. As you see there, the class Protocol itself doesn't do anything, because every method just casts self to protocol_t and calls a function. In fact, as can be seen from the function _read_images and others in objc-runtime-new.mm, the isa pointer of a Protocol object is set by hand when the executable and libraries are loaded, and never used.
So, don't try to inspect whether an id is a Protocol or not.
If you really need to do this, you can use
id foo=...;
if(foo->isa==class_getClass("Protocol")){
...
}
But, seriously, don't do it.
This is not an issue 'caused by inability to determine whether it's class or protocol. The error is 'caused by missing interface of Protocol class. Make sure you import Protocol.m at the top of your implementation file where you're testing argument's type.
You can also try using NSClassFromString() function which will return Class object or nil. Do note though that if nil is returned it doesn't mean that argument is protocol. It just means that it could be undefined class too!
There is also method NSProtocolFromString which returns appropriate results - Protocol for protocol and nil for undefined protocol.

What is the point of Protocols?

I've been writing various stuff using protocols as per example code, but also using some third party stuff, and they seem to adopt quite different approaches. Some specifically adopt the protocols in the interface using
#interface myClass <myProtocol>
others don't do that at all and merely pass themselves and are then set as delegates, but the end result seems to be exactly the same. I've tried both, and they both work fine. If someone was able to explain this I'd be a happy camper! Thanks very much.
A protocol declares a set of messages that an object must respond to (or with #optional, can respond to). In Objective-C, its only point (almost)* is to allow the compiler to flag up warnings if you pass an object that doesn't implement all the methods of the protocol with the correct signatures.
Taking a simple example: NSMutalbeDictionary has a method -setObject:ForKey: which sets the value for a particular key. The key is declared as type id which means you can pass any object and the compiler will not complain. However, the documentation for the method says:
The key is copied (using copyWithZone:; keys must conform to the NSCopying protocol).
so if you pass an object that doesn't have a -copyWithZone: method, you will get a exception at run time saying the key does not respond to -copyWithZone:. It would have been nice if the compiler could have detected your error.
If Apple had declared the method
-(void)setObject:(id)anObject forKey:(id<NSCopying>)aKey;
the compiler would have known about the requirement for -copyWithZone: (it's the only method declared in NSCopying) and would have caught any instances of passing incompatible objects at compile time. I think the reason they didn't do that is for backward compatibility. If bbum is reading, he might know the real reason why not.
*I say "almost" because you can test to see if an object conforms to a protocol at run time.
Objective-C can do both static and dynamic typing, so that protocols aren’t really required for the usual use cases. You can always type your delegate as id and then send it whatever messages you want. (The compiler will warn you if you attempt to send a message that’s not visible from the current file. That’s about the only sanity check it can do for id-typed objects without doing advanced type inference.)
But narrowing the id type down with protocols is nice and recommended, because 1) the code is more readable, 2) the compiler will warn you if you try to send the delegate some bogus message and 3) you’ll get better code completion.
Also the Xcode Code Sense can be very helpful if you use protocols. Sometimes it will suggest the missing methods.