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.
Related
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.
I've encountered the following line in some code that I'm studying:
#property (nonatomic, strong) NSString <Optional> *name;
I don't understand declaring an optional attribute.
I do understand using the '#optional' directive for methods.
BTW: the code is from a library module vs a full app.
This looks like it's declaring the property as an NSString that conforms to a protocol named "Optional".
This isn't the same as #optional for methods, or an Optional Type in Swift - it's just the name given to the protocol. Whoever wrote it might want to rename the protocol so it doesn't conflict w/the other uses of the word.
So it's not just a typical NSString, but has additional explicit restrictions that it implements whatever the "Optional" protocol requires.
This way it won't cause problems if you call an "Optional" protocol method on the name NSString instance, only to discover that it doesn't know what you're talking about.
See this answer on the use of Protocols as a Type.
This is also possible in Swift w/o the additional bracket notation - you can just use the name of the protocol as a Type.
I think that both methods are equivalent.
Do you know the difference?
objc_arc_weak_unavailable objc_arc_weak_unavailable attribute on
the class's interface declaration. A retainable object pointer type is
weak-unavailable if is a pointer to an (optionally protocol-qualified)
Objective-C class T where T or one of its superclasses has the
objc_arc_weak_unavailable attribute. A program is ill-formed if it
applies the __weak ownership qualifier to a weak-unavailable type or
if the value operand of a weak assignment operation has a
weak-unavailable type.
supportsWeakPointers If you you [sic] find that you must
implement custom retain or release methods, then you must also
implement the following method in your class:
-(BOOL)supportsWeakPointers { return NO; }
This method will prevent weak pointers from being formed to your objects. You are strongly encouraged to find a solution that doesn’t
require implementing your own retain and release methods instead of
doing this.
Note: By checking the LLVM parser I found that the right symbol is objc_arc_weak_reference_unavailable, that is:
__attribute__((objc_arc_weak_reference_unavailable))
#interface Point : NSObject
#end
Significantly, objc_arc_weak_unavailable is a compile time option (you can also declare it using NS_AUTOMATED_REFCOUNT_WEAK_UNAVAILABLE) whereas supportWeakPointers is a runtime call. This question addresses why you might use this.
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.
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.