How to reference Protocol in Objective-C? - objective-c

I know the directive for a protocol is #protocol just like #selector, but what is the "type" for referencing a Protocol (eg. SEL for #Selector)? In MacOSX stack, it's Protocol *?

You reference it as:
id<TheNameOfTheProtocol> aVariableToThatProtocol;
Or if a message wants a (Protocol *) object:
[myObject conformsToProtocol:#protocol(TheNameOfTheProtocol)];

id <YourProtocol> delegate(which is used to reference the protocol)?
I referred to the apple's official DOC, and found an simple example to refer to other protocols in a protocol:
#import "B.h"
#protocol B; // To break the recursive cycle, you must use the #protocol directive to make a forward reference to the needed protocol instead of importing the interface file where the protocol is defined
#protocol A
- foo:(id <B>)anObject;
#end
where protocol B is declared like this:
#import "A.h"
#protocol B
- bar:(id <A>)anObject;
#end
Note that using the #protocol directive in this manner simply informs the compiler that B is a protocol to be defined later. It doesn’t import the interface file where protocol B is defined.
And here're more things you'd like to know about protocol:
In many ways, protocols are similar to class definitions. They both declare methods, and at runtime they’re both represented by objects—classes by instances of Class and protocols by instances of Protocol. Like class objects, protocol objects are created automatically from the definitions and declarations found in source code and are used by the runtime system. They’re not allocated and initialized in program source code.
Source code can refer to a protocol object using the #protocol() directive—the same directive that declares a protocol, except that here it has a set of trailing parentheses. The parentheses enclose the protocol name:
Protocol *myXMLSupportProtocol = #protocol(MyXMLSupport);
This is the only way that source code can conjure up a protocol object. Unlike a class name, a protocol name doesn’t designate the object—except inside #protocol().
And what's more, the protocol is possible to check whether an object conforms to a protocol by sending it a conformsToProtocol: message:
if ( ! [receiver conformsToProtocol:#protocol(MyXMLSupport)] ) {
// Object does not conform to MyXMLSupport protocol
// If you are expecting receiver to implement methods declared in the
// MyXMLSupport protocol, this is probably an error
}
The conformsToProtocol: test is like the respondsToSelector: test for a single method, except that it tests whether a protocol has been adopted (and presumably all the methods it declares implemented) rather than just whether one particular method has been implemented. Because it checks for all the methods in the protocol, conformsToProtocol: can be more efficient than respondsToSelector:.
The conformsToProtocol: test is also like the isKindOfClass: test, except that it tests for a type based on a protocol rather than a type based on the inheritance hierarchy.

It's the same as on OS X:
Protocol * p = objc_getProtocol("UITableViewDataSource");
It's declared in <objc/runtime.h>:
typedef struct objc_object Protocol;

Related

Type "SwiftClass" cannot conform to protocol "ObjcProtocol" because it has requirements that cannot be satisfied

I have an Objective-C protocol which I'm trying to implement in a Swift class. For example:
#class AnObjcClass;
#protocol ObjcProtocol <NSObject>
- (void)somethingWithAnArgument:(AnObjcClass *)arg;
#end
When I try to conform to it in a Swift class like this:
#objc class SwiftClass: NSObject, ObjcProtocol {
// ...
}
I get the following scary compiler error:
Type "SwiftClass" cannot conform to protocol "ObjcProtocol" because it has requirements that cannot be satisfied.
How do I resolve this?
Ensure any classes referenced by that protocol are included in your bridging header.
This error happens when one of the types used in the protocol (the protocol itself, a return type, an argument type) is not included in your Swift bridging header.
Objective-C classes can happily implement this protocol because of the #class AnObjcClass forward declaration, but it appears that Swift classes can't implement protocols which use classes that are only forward-declared.

What is the point in having protocols if they are not checked?

I'm going through the book about Cocoa and Objective C ("Aaron Hillegass, Adam Preble - Cocoa Programming for Mac OS X - 2012") and when I did the example with NSTableView, I noticed that it really doesn't matter if I define my class as conforming to NSTableViewDataSource, NSTableViewDelegate protocols or omit them, only methods matter. (looks like sort of duck typing)
That is, the application works fine with both definitions:
#interface SpeakLineAppDelegate : NSObject <NSApplicationDelegate, NSSpeechSynthesizerDelegate, NSTableViewDataSource, NSTableViewDelegate>
and
#interface SpeakLineAppDelegate : NSObject <NSApplicationDelegate, NSSpeechSynthesizerDelegate>
It only yells at me at runtime if I don't implement 2 essential methods which are defined in NSTableViewDataSource, and in any case it doesn't matter at all if I put these protocols in class definition or not. So, what is the point in having them in the language? If they are only for documentation, we could put their names in comments as well, right? Or I'm missing something important here?
Protocol conformance can be checked at compile-time and runtime. Like most people said in the comments, protocol conformance is checked at compile-time. If you assign a type that doesn't conform to the protocol (other than id) to a variable of type bracketed with that protocol, the compiler should give you a warning. So in order to be able to pass an object that doesn't conform to a protocol to a parameter of that parameter type, you must have either 1) ignored a warning, or 2) gone through type id, which turns off static type checking.
The API you call also could (if it wanted to) check at runtime whether your objects formally conform to the protocol or not, using conformsToProtocol:. However, the convention in Cocoa is that the APIs never check for formal conformance to the protocol, but rather only check that it responds to a given selector when it needs to call it. This gives more flexibility to the user to, for example, use a class object (metaclasses can't formally conform to protocols, other than the ones conformed to by the root class) as a delegate.

Cannot adopt WebKit protocols

#import <WebKit/WebKit.h>
#interface MyClass : NSObject <WebFrameLoadDelegate> {
WebView *webView;
}
cannot find protocol declaration for 'WebFrameLoadDelegate'
WebFrameLoadDelegate is a informal protocol - it is declared as a category of NSObject. To use it you need to declare required methods in class interface and implement them.
When used to declare a protocol, a
category interface doesn’t have a
corresponding implementation. Instead,
classes that implement the protocol
declare the methods again in their own
interface files and define them along
with other methods in their
implementation files.
Directly from Apple Developer Reference:
https://developer.apple.com/library/mac/#documentation/Cocoa/Reference/WebKit/Protocols/WebFrameLoadDelegate_Protocol/Reference/Reference.html#//apple_ref/doc/uid/TP40003828
...However, depending on the content being loaded, some of the other methods defined in this protocol may be invoked multiple times. All the methods in this protocol are optional.
So the before answer is not correct in the sense of that it is not necessary to implement all the methods.

What are the angle brackets "<…>" in an Obj-C class interface for?

Can anyone tell me what the angle brackets <...> in an Objective-C class interface do? Like this one (from http://snipt.net/robhawkes/cocoa-class-interface):
#interface MapMeViewController : UIViewController <CLLocationManagerDelegate,
MKReverseGeocoderDelegate, MKMapViewDelegate, UIAlertViewDelegate> { ... }
From my view they look like some sort of type declaration (considering my previous experience in PHP and JavaScript), like we're making sure MapMeViewController is a CLLocationManagerDelegate, MKReverseGeocoderDelegate, MKMapViewDelegate, or UIAlertViewDelegate
Documentation about the #interface syntax don't seem to mention this.
The angle brackets in a class interface definition indicates the protocols that your class is conforming to.
A protocol is almost like an interface in Java or C#, with the addition that methods in an Objective-C protocol can be optional.
Additionaly in Objective-C you can declare a variable, argument or instance variable to conform to several protocols as well. Example
NSObject<NSCoding, UITableViewDelegate> *myVariable;
In this case the class must be NSObject or a subclass (only NSProxy and its subclasses would fail), and it must also conform to both NSCoding and UITableViewDelegate protocols.
In Java or C# this would only be possible by actually declaring said class.
The angle brackets indicate a protocol. They're analogous to interfaces in other languages.
You can also use them in code like a cast to tell the complier to expect an object that conforms to a particular protocol.
id <NSFetchedResultsSectionInfo> sectionInfo = [[self.noteFetcher sections] objectAtIndex:section];
Apple documentation reports the use of brackets; see The Objective-C Programming Language on the chapter 4, on "Adopting a Protocol".
Adopting a protocol is similar in some ways to declaring a superclass. Both assign methods to the class. The superclass declaration assigns it inherited methods; the protocol assigns it methods declared in the protocol list. A class is said to adopt a formal protocol if in its declaration it lists the protocol within angle brackets after the superclass name:
#interface ClassName : ItsSuperclass < protocol list >
Categories adopt protocols in much the same way:
#interface ClassName ( CategoryName ) < protocol list >

Defining categories for protocols in Objective-C?

In Objective-C, I can add methods to existing classes with a category, e.g.
#interface NSString (MyCategory)
- (BOOL) startsWith: (NSString*) prefix;
#end
Is it also possible to do this with protocols, i.e. if there was a NSString protocol, something like:
#interface <NSString> (MyCategory)
- (BOOL) startsWith: (NSString*) prefix;
#end
I want to do this since I have several extensions to NSObject (the class), using only public NSObject methods, and I want those extensions also to work with objects implementing the protocol .
To give a further example, what if I want to write a method logDescription that prints an object's description to the log:
- (void) logDescription {
NSLog(#"%#", [self description]);
}
I can of course add this method to NSObject, but there are other classes that do not inherit from NSObject, where I'd also like to have this method, e.g. NSProxy. Since the method only uses public members of protocol , it would be best to add it to the protocol.
Edit: Java 8 now has this with "virtual extension methods" in interfaces: http://cr.openjdk.java.net/~briangoetz/lambda/Defender%20Methods%20v4.pdf. This is exactly what I would like to do in Objective-C. I did not see this question earning this much attention...
Regards,
Jochen
Short answer: No.
Long answer: how would this work? Imagine you could add methods to existing protocols? How would this work? Imagine we wanted to add another method to NSCoding, say -(NSArray *) codingKeys; This method is a required method that returns an array of the keys used to encoding the object.
The problem is that there are existing classes (like, say NSString) that already implement NSCoding, but don't implement our codingKeys method. What should happen? How would the pre-compiled framework know what to do when this required message gets sent to a class that does not implement it?
You could say "we can add the definition of this method via a category" or "we could say that any methods added via these protocol categories are explicitly optional". Yes, you could do this and theoretically get around the problem I've described above. But if you're going to do that, you might as well just make it a category in the first place, and then check to make sure the class respondsToSelector: before invoking the method.
While it's true that you can't define categories for protocols (and wouldn't want to, because you don't know anything about the existing object), you can define categories in such a way that the code only applies to an object of the given type that has the desired protocol (sort of like C++'s partial template specialization).
The main use for something like this is when you wish to define a category that depends on a customized version of a class. (Imagine that I have UIViewController subclasses that conform to the Foo protocol, meaning they have the foo property, my category code may have need of the foo property, but I can't apply it to the Foo protocol, and if I simply apply it to UIViewController, the code won't compile by default, and forcing it to compile means someone doing introspection, or just screwing up, might call your code which depends on the protocol. A hybrid approach could work like this:
#protocol Foo
- (void)fooMethod
#property (retain) NSString *foo;
#end
#implementation UIViewController (FooCategory)
- (void)fooMethod {
if (![self conformsToProtocol:#protocol(Foo)]) {
return;
}
UIViewController<Foo> *me = (UIViewController<Foo>*) self;
// For the rest of the method, use "me" instead of "self"
NSLog(#"My foo property is \"%#\"", me.foo);
}
#end
With the hybrid approach, you can write the code only once (per class that is supposed to implement the protocol) and be sure that it won't affect instances of the class that don't conform to the protocol.
The downside is that property synthesis/definition still has to happen in the individual subclasses.
extObjC has the NEATEST stuff you can do with Protocols / Categories... first off is #concreteprotocol...
Defines a "concrete protocol," which can provide default implementations of methods within protocol.
An #protocol block should exist in a header file, and a corresponding #concreteprotocol block in an implementation file.
Any object that declares itself to conform to this protocol will receive its method implementations, but only if no method by the same name already exists.
MyProtocol.h
#protocol MyProtocol
#required - (void)someRequiredMethod;
#optional - (void)someOptionalMethod;
#concrete - (BOOL)isConcrete;
MyProtocol.m
#concreteprotocol(MyProtocol) - (BOOL)isConcrete { return YES; } ...
so declaring an object MyDumbObject : NSObject <MyProtocol> will automatically return YES to isConcrete.
Also, they have pcategoryinterface(PROTOCOL,CATEGORY) which "defines the interface for a category named CATEGORY on a protocol PROTOCOL". Protocol categories contain methods that are automatically applied to any class that declares itself to conform to PROTOCOL." There is an accompanying macro you also have to use in your implementation file. See the docs.
Last, but NOT least / not directly related to #protocols is
synthesizeAssociation(CLASS, PROPERTY), which "synthesizes a property for a class using associated objects. This is primarily useful for adding properties to a class within a category. PROPERTY must have been declared with #property in the interface of the specified class (or a category upon it), and must be of object type."
So many of the tools in this library open (way-up) the things you can do with ObjC... from multiple inheritance... to well, your imagination is the limit.
It isn't really meaningful to do so since a protocol can't actually implement the method. A protocol is a way of declaring that you support some methods. Adding a method to this list outside the protocol means that all "conforming" classes accidentally declare the new method even though they don't implement it. If some class implemented the NSObject protocol but did not descend from NSObject, and then you added a method to the protocol, that would break the class's conformance.
You can, however, create a new protocol that includes the old one with a declaration like #protocol SpecialObject <NSObject>.
I think you may be mixing up terms here and there. Extensions, Categories, Protocols, Interfaces and Classes are all different things in Objective-C. In The Objective-C 2.0 Language Apple describes the differences very well, including the benefits and drawbacks to using categories and extensions.
If you think about it, what is a "Category" or "Extension" in the conceptual sense? It's a way of adding functionality to a Class. In Objective-C, protocols are designed to have no implementation. Therefore, how would you add or extend the implementation of something that doesn't have implementation to begin with?
if you're already writing a category, why not just add in the protocol definition in the header right after the category definition?
i.e.
#interface NSString (MyCategory)
- (BOOL) startsWith: (NSString*) prefix;
#end
#protocol MyExtendedProtocolName <NSString>
//Method declarations go here
#end
this way any class that imports the category header will also get the protocol definition, and you can add it into your class..
#interface MyClass <OriginalProtocol,MyExtendedProtocolName>
also, be careful when subclassing NSString, it's a cluster and you may not always get the behaviour you're expecting.
Adam Sharp posted a solution that worked for me.
It involves 3 steps:
Defining the methods you want to add as #optional on a protocol.
Making the objects you want to extend conform to that protocol.
Copying those methods into those objects at runtime.
Check out the link for the full details.