Iphone Objective-C中的Javascript样式对象
背景:我在iPhone和iPad代码中使用了大量NSDictionary对象。我厌倦了获取/设置这些状态字典的键的冗长方式 所以做了一个小小的实验:我刚刚创建了一个我称之为Remap的类 重新映射将获取任意集合[VariableName]:(NSObject*)obj选择器,并将该消息转发给将在[vairableName]键下将obj插入内部NSMutableDictionary的函数 重新映射还将采用任意(零参数)的[variableName]选择器,并返回在NSMutableDictionary中键[variableName]下映射的NSObject e、 g 其中,testNumber、testString或testDict属性实际上都未在Remap中定义 疯狂的事?它是有效的。。。我唯一的问题是如何禁用“可能不响应”警告,以便仅访问重新映射 注:我可能会放弃这个,使用宏,因为消息转发效率很低。。。但除此之外,有没有人看到重拍的其他问题 这是为那些好奇的人准备的Remap's.m:Iphone Objective-C中的Javascript样式对象,iphone,objective-c,xcode,ipad,suppress-warnings,Iphone,Objective C,Xcode,Ipad,Suppress Warnings,背景:我在iPhone和iPad代码中使用了大量NSDictionary对象。我厌倦了获取/设置这些状态字典的键的冗长方式 所以做了一个小小的实验:我刚刚创建了一个我称之为Remap的类 重新映射将获取任意集合[VariableName]:(NSObject*)obj选择器,并将该消息转发给将在[vairableName]键下将obj插入内部NSMutableDictionary的函数 重新映射还将采用任意(零参数)的[variableName]选择器,并返回在NSMutableDictiona
#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 = [NSString stringWithUTF8String: sel_getName([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 = [NSString stringWithUTF8String: sel_getName(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 training :
range.location = 4;
NSString * adjustedKey = [NSString stringWithFormat:@"%@%@", firstChar, [key substringWithRange:range]];
[[self _data] setObject:data forKey:adjustedKey];
}
else
{
//assert?
}
}
@end
作为使字典更像通用对象的一种替代方法,我所做的是创建NSDictionary的类别,为特定键包装getter和setter。只需使用非常描述性的名称,因为您正在填充一个全局名称空间
@interface NSDictionary (MyGetters)
@property (nonatomic,readonly) id something;
-(id) something;
@end
@interface NSDictionary (MyGetters)
-(id) something { return [self objectForKey:@"something"]; }
@end
@interface NSMutableDictionary (MySetters)
-(void) setSomething:(id)inValue;
@end
@interface NSDictionary (MySetters)
-(void) setSomething:(id)inValue { return [self setObject:inValue forKey:@"something"]; }
@end
setter属性的唯一问题是必须在这两个类别中定义getter以避免警告
您仍然必须声明所有内容,但无论如何您都必须这样做才能消除重新映射的警告。如果我正确地阅读了您的代码,我认为这种方法的一个潜在问题可能是您不能使用诸如
哈希
(或来自NSObject
的其他方法,假设您的Remap
继承自NSObject
)。您将得到Remap
实例的哈希值,而不是让Remap
在\u data
中查找名为hash
的键,因为[Remap hash]据我所知,
不会调用forwardIncovation:
。很酷的类。我喜欢它
我想不出抑制所有警告的方法,但我们可以将其减少到每个属性一行。将此添加到重新映射中。h:
#define RemapProperty(PROP) \
@interface Remap(PROP) \
@property (nonatomic, retain) id PROP; \
@end \
@implementation Remap(PROP) \
@dynamic PROP; \
@end
现在,您可以通过将以下内容放在发出警告的文件的顶部来抑制给定属性的所有重新映射警告:
RemapProperty(propertyName);
这需要一些额外的工作,但它给了您点语法作为奖励
remap.propertyName = @"Foo";
只需再做一点工作,您就可以定义一个类似的宏,直接将属性添加到NSDictionary,从而不需要重新映射类。作为旁注,您可以使用
NSSelectorFromString
从NSStrings获取选择器,也可以使用NSStringFromSelector
从Selector获取NSStringsd调用。我会更改它,谢谢。解决这个问题的方法是调用[super respondsToSelector:],并且只将不支持的选择器视为键。@dragonward实际上NSObject的哈希仍然会被调用,因为[super methodSignatureForSelector:aSelector](其中aSelector==@selector(哈希))将找到一个现有函数,而不输入我的代码。作为一个强力操作,我可以覆盖NSObject的每个属性,并确保它调用我的函数。(当然……如果我真的想调用NSObject的哈希,这将是一个问题……但我可以接受这个限制)。是的,我也考虑过这个问题。但实际上,我正试图找到最终的解决方案,以避免每次需要字典中的新值时都必须编写代码。最终的解决方案是通过添加支持语言的对象来更改编译器的工作方式。当您这样做时,是否可以添加常量nsarray:@[“a”、“b”、“c”];因为我也很喜欢这个功能。谢谢,好主意。这使得“重新映射”几乎可以使用……也许我会做一些基准测试,看看我会受到多大的性能影响。
remap.propertyName = @"Foo";