How to add a property via class category?

Featured Image

Have you ever been in a situation where you needed to extend class with additional property but for some organizational reason you didn’t want to change default source class file? For example, when you add Xcode sub-project which you want to keep untouched and up-to date with it’s version control, but still you want to make certain default implementation changes in sub-project.

Directly changing sub-project source files would end up with very painful merging after version control update. Sub-classing default class to add one more property is also painful experience comparing to Objective-C categories pattern (you would need to change class name everywhere you made an instance of default class). It’s true that in class category you can not declare iVar’s or makeĀ @synthesize but nevertheless you CAN extend class with another property by drilling down all to runtime.h. Below you can see example.

@interface SomeClass (Private)
 
@property (nonatomic, assign) id newProperty;
 
@end
 
NSString * const kNewPropertyKey = @"kNewPropertyKey";
 
@implementation SomeClass (Private)
 
@dynamic newProperty;
 
- (void)setNewProperty:(id)aObject
{
	objc_setAssociatedObject(self, kNewPropertyKey, aObject, OBJC_ASSOCIATION_ASSIGN);
}
 
- (id)newProperty
{
	return objc_getAssociatedObject(self, kNewPropertyKey);
}
 
@end

This way you can have always keep your Xcode sub-project up-to date without painful merging. Also, it’s easier but not recommended to use categories over sub-classing pattern when you need to overwrite default class implementation (good only in cases you know what’s get overwritten).

In contrast to Objective-C class Extensions this way you don’t have to re-declare property that is publicly declared in default class. In Objective-C class Extensions it is also generally common for a class to have a publicly declared API and to then have additional methods declared privately for use solely by the class or the framework within which the class resides. Class extensions allow you to declare additional required methods for a class in locations other than within the primary class @interface block.

@interface MyClass : NSObject
 
@property (retain, readonly) float value;
 
@end
 
// Private extension, typically hidden in the main implementation file.
 
@interface MyClass ()
 
@property (retain, readwrite) float value;
 
@end
 
@interface MyClass : NSObject
 
- (float)value;
 
@end
 
@interface MyClass () {
 
    float value;
 
}
 
- (void)setValue:(float)newValue;
 
@end
 
@implementation MyClass
 
- (float)value {
 
    return value;
 
}
 
- (void)setValue:(float)newValue {
 
    value = newValue;
 
}
 
@end

The implementation of the setValue: method must appear within the main @implementation block for the class (you cannot implement it in a category). If this is not the case, the compiler emits a warning that it cannot find a method definition for setValue:. Therefore you should use objc_getAssociatedObject & objc_setAssociatedObject to make’s your development way easier.


3 comments

Leave a Reply

Your email address will not be published. Required fields are marked *

You may use these HTML tags and attributes: <a href="" title=""> <blockquote cite=""> <code> <del datetime=""> <em> <s> <strike> <strong>. You may use following syntax for source code: <pre><code>$current = "Inchoo";</code></pre>.