Skip to content

Instantly share code, notes, and snippets.

@xareelee
Last active May 2, 2019 13:43
Show Gist options
  • Save xareelee/5c7877a9a5655db65607 to your computer and use it in GitHub Desktop.
Save xareelee/5c7877a9a5655db65607 to your computer and use it in GitHub Desktop.
Objective-C property name to a string with autocompletion and compile-time check
// Release under MIT
// Copyright (C) 2015 Xaree Lee
#import <Foundation/Foundation.h>
/* Get property name for the class (C string or NSSting). */
#define keypathForClass(Klass, PropertyName) \
(((void)(NO && ((void)[Klass _nullObjectForCheckingPropertyName].PropertyName, NO)), # PropertyName))
#define keypathStringForClass(Klass, PropertyName) \
@keypathForClass(Klass, PropertyName)
/* Get property name for the protocol (C string or NSSting). */
#define keypathForProtocol(Protocol, PropertyName) \
(((void)(NO && ((void)((NSObject<Protocol> *)[NSObject _nullObjectForCheckingPropertyName]).PropertyName, NO)), # PropertyName))
#define keypathStringForProtocol(Protocol, PropertyName) \
@keypathForProtocol(Protocol, PropertyName)
@interface NSObject (PropertyName)
+ (instancetype)_nullObjectForCheckingPropertyName;
@end
// Release under MIT
// Copyright (C) 2015 Xaree Lee
#import "NSObject+PropertyName.h"
@implementation NSObject (PropertyName)
+ (instancetype)_nullObjectForCheckingPropertyName;{
return nil;
}
@end

Getting a string value for a property of a class with autocompletion feature and checking it at compile-time is very useful.

Discussion

This gist demonstrates a simple idea using null-object pattern and the trick of keypath(...) derived from libextobjc and ReactiveCocoa to get the property name from a class.

Although the compiler should ignore the ((void)(NO && ((void)<#_ObjC_Message_#>, NO)) statement at compile-time, the method +_nullObjectForCheckingPropertyName still guarantees that the getter method in <#_ObjC_Message_#> will not be invoked to prevent if from any possible side effect.

License

Release under MIT.

How to use:

  • Include NSObject+PropertyName.h and NSObject+PropertyName.m in your project.
  • Get the property name for a class using the macro:
#import "NSObject+PropertyName.h"

@interface AnyClass : NSObject
@property (strong) NSData *data;
@end

// Bad approach (no autocompletion; no compile-time check):
NSString *propertyName = @"data";

// == My approach ==
// C string for a class
keypathForClass(AnyClass, data);        // ==> "data"
// NSString for a class
@keypathForClass(AnyClass, data);       // ==> @"data"
keypathStringForClass(AnyClass, data);  // ==> @"data" (alternative way)
  • Get the property name for a protocol using the macro:
#import "NSObject+PropertyName.h"

@protocol AnyProtocol
@property (strong) NSDate *date;
@end

// C string for a protocol
keypathForProtocol(AnyProtocol, date);        // ==> "date"
// NSString for a protocol
@keypathForProtocol(AnyProtocol, date);       // ==> @"date"
keypathStringForProtocol(AnyProtocol, date);  // ==> @"date" (alternative way)
@xareelee
Copy link
Author

Yes, It's now released under MIT.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment