Is it possible to add properties to an Objective C object at runtime?
-
if it is compliant to KVC protocol - it is possible – Nekto Oct 19 '11 at 09:23
-
What exactly do you mean by properties? Objective-C declared properties? – Oct 19 '11 at 22:30
3 Answers
It’s possible to add formal properties to a class via class_addProperty()
:
BOOL class_addProperty(Class cls,
const char *name,
const objc_property_attribute_t *attributes,
unsigned int attributeCount)
The first two parameters are self-explanatory. The third parameter is an array of property attributes, and each property attribute is a name-value pair which follow Objective-C type encodings for declared properties. Note that the documentation still mentions the comma-separated string for the encoding of property attributes. Each segment in the comma-separated string is represented by one objc_property_attribute_t
instance. Furthermore, objc_property_attribute_t
accepts class names besides the generic @
type encoding of id
.
Here’s a first draft of a program that dynamically adds a property called name
to a class that already has an instance variable called _privateName
:
#include <objc/runtime.h>
#import <Foundation/Foundation.h>
@interface SomeClass : NSObject {
NSString *_privateName;
}
@end
@implementation SomeClass
- (id)init {
self = [super init];
if (self) _privateName = @"Steve";
return self;
}
@end
NSString *nameGetter(id self, SEL _cmd) {
Ivar ivar = class_getInstanceVariable([SomeClass class], "_privateName");
return object_getIvar(self, ivar);
}
void nameSetter(id self, SEL _cmd, NSString *newName) {
Ivar ivar = class_getInstanceVariable([SomeClass class], "_privateName");
id oldName = object_getIvar(self, ivar);
if (oldName != newName) object_setIvar(self, ivar, [newName copy]);
}
int main(void) {
@autoreleasepool {
objc_property_attribute_t type = { "T", "@\"NSString\"" };
objc_property_attribute_t ownership = { "C", "" }; // C = copy
objc_property_attribute_t backingivar = { "V", "_privateName" };
objc_property_attribute_t attrs[] = { type, ownership, backingivar };
class_addProperty([SomeClass class], "name", attrs, 3);
class_addMethod([SomeClass class], @selector(name), (IMP)nameGetter, "@@:");
class_addMethod([SomeClass class], @selector(setName:), (IMP)nameSetter, "v@:@");
id o = [SomeClass new];
NSLog(@"%@", [o name]);
[o setName:@"Jobs"];
NSLog(@"%@", [o name]);
}
}
Its (trimmed) output:
Steve
Jobs
The getter and setter methods should be written more carefully but this should be enough as an example of how to dynamically add a formal property at runtime.
-
1class_addProperty returns true, but class_getInstanceVariable always returns nil. I've tried putting the property name instead of the ivar name, but still no luck. Any idea what could be the issue? – Mercurial Jul 26 '13 at 18:42
-
1@Bavarious, how did you fool complier? I mean [o name] results in compilation error 'No known instance method for selector 'name''. – Hitesh Savaliya Sep 26 '13 at 16:00
-
@HiteshSavaliya a long time ago (before ARC) this was just possible. nowadays you'd have to at least declare the `-name` selector. – Michael Aug 25 '14 at 15:18
-
@Michael : Nope, you can just fool the compiler using performSelector: on your class ! – Perceval Apr 18 '15 at 06:33
-
1@PercevalFARAMAZ: yeah, because ARC is mostly a compile-time feature... and -performSelector: has been declared and is visible to the compiler. Before ARC, you could do it without -performSelector: , with ARC you can't. That's what I said and it's still true. there are 100 ways to circumvent every ARC restriction, e.g. calling `[self performSelector:NSSelectorFromString(@"retain")]` in place of `[self retain]`. ARC is a safety feature, not a security feature! And -performSelector is no more elegant than just declaring the selector IMHO. – Michael Apr 19 '15 at 10:12
-
@Michael : It may not be more convenient, but it's good to know if you're dynamically adding new selectors without knowing their name (see http://github.com/perfaram/NVRAM-Dynamic-Class) – Perceval Apr 19 '15 at 13:38
-
1@PercevalFARAMAZ: if you don't know the selector at compile time, you have to use something like -performSelector: anyways, regardless of ARC. The original discussion here was about `[o name]` giving a compiler error 'No known instance method for selector 'name'' => that's an ARC issue. without ARC, calling `[o name]` is just possible, that's what I said. With ARC you have to do something different, e.g. -performSelector:, or declare the `-name` selector. understand? – Michael Apr 19 '15 at 17:55
-
@Michael : i *do* totally agree with you ! I was just showing a way to do it with ARC enabled – Perceval Apr 23 '15 at 08:59
If you take a look at NSKeyValueCoding
protocol, documented here, you can see that there is a message called:
- (id)valueForUndefinedKey:(NSString *)key
You should override that method to provide your custom result for the specified undefined property. Of course this assumes that your class uses the corresponding protocol.
This kind of approach is commonly uses to provide unknown behavior to classes (eg. a selector that doesn't exist).

- 131,802
- 30
- 241
- 343
@properties - no (i.e. using dot syntax etc). But you can add storage using using associated objects: How do I use objc_setAssociatedObject/objc_getAssociatedObject inside an object?.

- 1
- 1

- 15,389
- 6
- 48
- 59