Skip to content

Instantly share code, notes, and snippets.

@adamawolf
Created May 29, 2010 01:52
Show Gist options
  • Save adamawolf/417955 to your computer and use it in GitHub Desktop.
Save adamawolf/417955 to your computer and use it in GitHub Desktop.
An Objective-C data structure that accepts setVariableName: and variableName messages without declaring a variableName property.
#import "Remap.h"
//to suppress warnings
RemapProperty(sampleText);
RemapProperty(sampleDict);
#define kKey_SampleText @"sampleTextKey"
int main()
{
Remap * remap = [[Remap alloc] init];
[remap setSampleText:@"example"];
[remap setSampleDict:[NSDictionary dictionaryWithObject:[remap sampleText] forKey:kKey_SampleText]];
NSLog(@"%@", [[remap sampleDict] objectForKey:kKey_SampleText]);
return 1;
}
//
// Remap.m
//
// Created by Adam Wolf on 5/24/10.
//
#import "Remap.h"
@interface Remap ()
@property (nonatomic, retain) NSMutableDictionary * _data;
@end
@implementation Remap
@synthesize _data;
- (void) dealloc
{
relnil(_data);
[super dealloc];
}
- (id) init
{
self = [super init];
if (self != nil) {
NSMutableDictionary * dict = [[NSMutableDictionary alloc] init];
[self set_data:dict];
relnil(dict);
}
return self;
}
- (void)forwardInvocation:(NSInvocation *)anInvocation
{
NSString * selectorName = NSStringFromSelector([anInvocation selector]);
NSRange range = [selectorName rangeOfString:@"set"];
NSInteger numArguments = [[anInvocation methodSignature] numberOfArguments];
if (range.location == 0 && numArguments == 4)
{
//setter
[anInvocation setSelector:@selector(setData:withKey:)];
[anInvocation setArgument:&selectorName atIndex:3];
[anInvocation invokeWithTarget:self];
}
else if (numArguments == 3)
{
[anInvocation setSelector:@selector(getDataWithKey:)];
[anInvocation setArgument:&selectorName atIndex:2];
[anInvocation invokeWithTarget:self];
}
}
- (NSMethodSignature *) methodSignatureForSelector:(SEL) aSelector
{
NSString * selectorName = NSStringFromSelector(aSelector);
NSMethodSignature * sig = [super methodSignatureForSelector:aSelector];
if (sig == nil)
{
NSRange range = [selectorName rangeOfString:@"set"];
if (range.location == 0)
{
sig = [self methodSignatureForSelector:@selector(setData:withKey:)];
}
else
{
sig = [self methodSignatureForSelector:@selector(getDataWithKey:)];
}
}
return sig;
}
- (NSObject *) getDataWithKey: (NSString *) key
{
NSObject * returnValue = [[self _data] objectForKey:key];
return returnValue;
}
- (void) setData: (NSObject *) data withKey:(NSString *)key
{
if (key && [key length] >= 5 && data)
{
NSRange range;
range.length = 1;
range.location = 3;
NSString * firstChar = [key substringWithRange:range];
firstChar = [firstChar lowercaseString];
range.length = [key length] - 5; // the 4 we have processed plus the trailing :
range.location = 4;
NSString * adjustedKey = [NSString stringWithFormat:@"%@%@", firstChar, [key substringWithRange:range]];
[[self _data] setObject:data forKey:adjustedKey];
}
else
{
//assert?
}
}
@end
//
// Remap.h
//
// Created by Adam Wolf on 5/24/10.
//
// Meant as a wrapper around NSMutableDictionary to retrieve any arbitrary
// ivar access and store any arbitrary ivar set, regardless of if the ivar is
// define in the object.
#import <Foundation/Foundation.h>
@interface Remap : NSObject {
@private
NSMutableDictionary * _data;
}
#define RemapProperty(PROP) \
@interface Remap(PROP) \
@property (nonatomic, retain) id PROP; \
@end \
@implementation Remap(PROP) \
@dynamic PROP; \
@end
@end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment