I've come across an interesting issue and wasn't able to find any documentation on it... Sometimes properties
declared in a protocol
are not implemented in a particular class conforming to that protocol
and a runtime exception occurs. Are dynamic property
definitions optimized away under some strange circumstance? Can protocols
not be used with properties
that were made to be declared dynamic
? Any insight into this would be greatly appreciated.
Below are some more details.
Given a protocol
:
@protocol MyProtocol <NSObject>
@property (nonatomic, strong) id someProperty;
@end
and a class implementing the protocol
like so:
@interface MyClass <MyProtocol>
@end
@implementation MyClass
@dynamic someProperty;
@end
I've noticed that sometimes I am unable to get any information from calling
class_getProperty(myClass, propertyName);
for the properties
in the protocol
. This only happens to some classes and seems to be sporadic.
I'm running the latest Xcode 4 and linking against the iOS 6 SDK. I do have the pre-release Xcode 5 installed on the same machine though it is not the default (via xcode-select).
If you run this code:
@protocol MyProtocol <NSObject>
@property (nonatomic, strong) id someData;
@end
@interface MyObject : NSObject <MyProtocol>
@end
@implementation MyObject
@dynamic someData;
@end
and then you run
const char *name = [@"someData" UTF8String];
objc_property_t property = class_getProperty([MyObject class], name);
const char *attributes = property_getAttributes(property);
You WILL get meta data on the property
EVEN THOUGH the property
doesn't exist. In other words you don't need to synthesize the property to get it's attributes. The runtime still knows about it. Try it for yourself. The problem is that sometimes this doesn't happen. I want to know the conditions that cause the runtime to be unaware of the property
attributes.
My temporary fix is to just copy all the property
definitions in the protocol
and paste them into the .h file:
@interface MyClass <MyProtocol>
@property (nonatomic, strong) id someProperty;
@end
@implementation MyClass
@dynamic someProperty;
@end
This runs fine, though it is far from ideal. However, it suggests that my code is working correctly and the issue lies elsewhere.
I'd be happy to provide more details or background if needed.
protocols define methods, optional methods and required methods.
properties are abstracted methods, if the protocol defines a property as being required then you must implement the required methods: typically with @synthesize
... but can be done in other ways
(assuming non-fragile ABI / Modern Runtime) Using readonly for simplicity
@property(readonly)int dog;
could be implimented:
@synthesize dog;
or
@synthesize dog = _dog; // synthesize standard getter for the iVar _dog
or
- (int) dog
{
return _dog; // or dog, or cat/5 or 5 or whatever
}
EDIT: re dynamic properties
@dynamic
is a keyword that does nothing to generate methods to satisfy the requirement of a property, what it does do is inform the compiler that it is "taken care of" in some other way...
this dynamic dispatch can be accomplished by a few different methods at runtime, one would be by adding method implementations at run time, another would be by using the runtime for unresolved selectors. (I had a similar question about using dynamic properties to use a generic KV store in a Dictionary)
see: Using NSMutableDictionary as backing store for properties
There seems to be a confusion:
Declaring a property is enough for the property to exist at runtime. There is no need for implementation. This is how objective-c works. Methods don't have to exist at compile time, you can add them dynamically (e.g. what Core Data does).
@dynamic
does absolutely nothing during runtime. At compile-time it's a placeholder which says "don't give me compiler warnings that the getter/setter is not defined here". On the newest LLVM it also says "don't synthesize automatically".
My suggestions:
If you are adding the protocol via a category, make sure the category is loaded. This seems to be the most usual problem with runtime reflection.
To debug, also try to use class_conformsToProtocol
. It would be strange to have a class that conforms to a protocol without it having properties declared by the protocol.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With