How are protocols internally implemented? - objective-c

As far as I know, classes in Objective-C are stored in terms of C structures.
How are protocols implemented?
I'd like to understand this in simple terms.
What does [NSObject conformsToProtocol:] do to check whether a class conforms to the protocol or not?
Is there a table or data structure for a protocol that tells what selectors there are in a protocol?
NOTE: The term "protocol" here is used to refer to a Objective C construct not a network protocol.

If you look at the Objective-C Runtime Reference, you will see that there are several functions which allow you to retrieve & inspect the contents of a so-called Protocol struct.
These structs allow access into what a Protocol object contains and its property names should infer what their underlying purpose is.
Some of the members that a Protocol contain are as follows:
A list of objc_method_description structs.
A list of objc_property_t structs.
And of course a method called protocol_getName which will give you the name of the protocol itself.
I think this should be adequate in inferring for yourself how these protocols are implemented by the Objective-C compiler + runtime.
My idea for how they're actually implemented is that the compiler turns these so-called #protocol declarations into C structs at compile-time, and the Objective-C methods such as conformsToProtocol: simply perform comparisons on the members of the passed-in struct as generated by the #protocol language construct.
Therefore, you can do something like this:
#protocol BlahProtocol <NSObject>
-(void)blahMethod;
#property (nonatomic, strong) id blahProperty;
#end
//...
Protocol *blah = objc_getProtocol("BlahProtocol");
struct objc_method_description blahMethodDescription = protocol_getMethodDescription(blah, #selector(blahMethod), NO, YES);
NSLog(#"%s %s", blahMethodDescription.name, blahMethodDescription.types);
objc_property_t blahProperty = protocol_getProperty(blah, "blahProperty", NO, YES);
NSLog(#"%s", property_getAttributes(blahProperty));

protocols work by specifying that a certain method is invoked. You ask if the object 'respondsToSelector', to check if it implements a specific method, then you invoke it by invoking the method.

Related

RLMArray property declaration syntax

When declaring an RLMArray, what is the significance of the second set of brackets? Realm is the only place I've seen this used.
#property NSArray<NSDictionary*> *dictionaries; // I understand this (and it's wonderful!)
#property NSDictionary<NSString*, NSArray<NSString*>*> *dictionaryOfArraysOfStrings; // No problem with this either
#property RLMArray<Object*><Object> *objects; // What is <Object> for?
The two sets of angle brackets are for Objective-C generics and protocols respectively. Objective-C generics lets the compiler know that methods like -[RLMArray firstObject] return the specific type of object that the array contains, rather than any possible RLMObject subclass. Sadly this extra type information is erased at runtime, so Realm has no way to tell from the use of Objective-C generics alone in the property declaration what type of object the array contains. This is where the protocol conformance comes in. The protocol that a property conforms to is available to Realm at runtime, and so is used to inform Realm of the object type that your RLMArray property will contain. Realm provides the RLM_ARRAY_TYPE macro to declare a protocol of the same name as a model class, so it is easy to miss that a protocol is involved.

Use of TypeName<protocol_name> in variable declaration in Objective-C

Usually when it comes to declare a variable as a protocol it's done as follows:
id<protocol_name> variable;
But recently I've seen something that I don't fully understand. The compiler allows you to define things like:
NSString<protocol_name> *variable;
In fact assigning from other "plain" NSString variable will cause the compiler to warn you and you'll need to cast it.
I've seen it in JSONModel and the framework uses it to "annotate" properties.
But, apart from that what is it intended for? What are the benefits?
Thanks.
Benefits is with variable you can work as with NSString* and id<protocol_name>.
You may need all interfaces and don't need type casting.
"plain" NSString is not conform to protocol "protocol_name" and compiler doesn't allows that.
But you can make NSString conform protocol with categories:
#interface NSString(protocol_name) < protocol_name >
#end
Actually NSString<protocol_name> is bad example, because you can't subclass NSString.
With other classes that you can subclass, you can implement that protocol in childs.

How to reference Protocol in 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;

What is the different between an id and NSObject in Objective C?

What is the different between this:
id:
#import <objc/Object.h>
#interface Forwarder : Object
{
id something;
}
NSObject:
#import <objc/Object.h>
#interface Forwarder : Object
{
NSObject *something;
}
Thz u.
This Greg MILLER's blog post from the unixjunkie blog sums up the differences
Some extracts:
There's often confusion about the difference between the following three declarations in Objective-C:
id foo1;
NSObject *foo2;
id<NSObject> foo3;
The first one is the most common.
It simply declares a pointer to some Objective-C object (see /usr/include/objc/objc.h). id gives the compiler no information about the actual type of the object, so the compiler cannot do compile-time type checking for you.
Just because we know that an id is an Objective-C object does not mean that it points to an object that derives from NSObject, or that it even has common methods like retain and release.
One solution is to statically type our variable using NSObject* as shown in number 2 above.
This gives the compiler information about the class of the object pointed to by foo2 so the compiler can warn if you send a message to foo2 that an NSObject doesn't respond to. This means you can safely call retain, release, description, etc., but the compiler will warn if you call length or count or anything that an NSObject doesn't respond to.
Declaring an object as id<NSObject> tells the compiler that you don't care what type the object is, but you do care that it conforms to the specified NSObject protocol**.
** the protocol (#protocol) named NSObject. There is also a class named NSObject that does indeed conform to the NSObject protocol, but they are two different thing
The compiler will ensure that all objects you assign to that pointer conform to the required protocol.
A pointer typed like this can safely hold any NSObject (because NSObject conforms to the NSObject protocol), but it could also hold any NSProxy, because NSProxy also conforms to the NSObject protocol.
In english, the declaration id<NSObject> foo3; says "foo3 is a pointer to an object of any type that behaves like an NSObject".
This is very powerful, convenient, and expressive. In reality, we often don't care what type an object is, we just care that it responds to the messages that we want to send it (e.g., retain, release).
If you don't want (or can't have) any type checking, then use a plain id. This is very common for return types on methods that don't know the type of object they're returning (e.g., +alloc). It is also common to declare delegates to be type id, because delegates are generally checked at runtime with respondsToSelector:, and they usually aren't retained.
However, if you do want compile-time type checking, you must decide between the second and third cases. Well, let me just help you out—you want the third case! :-) I've very, very, VERY rarely seen a situation where NSObject * worked but id would not. And using the protocol form has the advantage that it will work with NSProxys.
The practical difference is that you do not need to typecast an id, but you usually need to typecast an NSObject * to something before using it. NSObject is the base class that almost all other classes are derived from where id is more of a language keyword.
An id responds to any method without a compiler warning; NSObjects only respond without warning to methods defined in NSObject, including the NSObject protocol.

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.