使用NSMutableDictionary作为属性的后备存储

Gra*_*yer 4 iphone cocoa objective-c ios

我正在寻找一种简单的方法来将我的属性直接设置为NSMutableDictionary,它是一个实例变量.即:

KVCModle.h:

@interface KVModel : NSObject {
    NSMutableDictionary * data;
}
@property(nonatomic,assign)NSString * string1;
@property(nonatomic,assign)NSString * string2;
@end
Run Code Online (Sandbox Code Playgroud)

KVCModel.m

#import "KVModel.h"


@implementation KVModel

-(id)init
{
    self = [super init];
    if(self)
    {
        data = [[NSMutableDictionary alloc] init];
    }
    return self;
}

-(NSString *)string1
{
    return [data objectForKey:@"string1"];
}
-(NSString *)string2
{
    return [data objectForKey:@"string2"];
}
-(void)setString1:(NSString *)_string1
{
    [data setObject:_string1 forKey:@"string1"];
}
-(void)setString2:(NSString *)_string2
{
    [data setObject:_string2 forKey:@"string2"];
}
-(void)dealloc
{
    [data release];
    [super dealloc];
}

@end
Run Code Online (Sandbox Code Playgroud)

我试图重写setValue:ForKey:valueForKey:,但这些都是不叫,它们允许你直接设置属性不使用属性语法.

我已经制作了预处理器宏来完成这项工作,但我根本不打算输入,并且希望将来尽可能多地避免使用它.有没有办法让我不熟悉这项工作?

我曾考虑使用NSManagedObject,但我不确定我能不能得到我想要的东西. 编辑: 来源

Pet*_*sey 8

如果你想用代码来访问类的性质foo = obj.fooobj.foo = foo,这就是为什么它不工作.

属性访问语法与消息语法同义; 前者完全相同foo = [obj foo],后者完全相同[obj setFoo:foo].没有KVC代码可以拦截.属性属于语言级别; KVC处于框架层面.

您需要拦截访问者消息.考虑实现resolveInstanceMethod:类方法,在你使用的Objective-C运行时API添加一个方法实现的类"解决"的选择.您可以为许多不同的选择器添加相同的实现.

为了您的目的,有一个函数或方法来检查选择器(使用NSStringForSelector和常规的NSString检查技术)并返回两个事实:(1)属性名称,以及(2)它是getter(foo,isFoo)还是setter(setFoo:).然后,有两个方法,一个是动态getter,另一个是动态setter.当选择器命名一个getter时,使用dynamic-getter方法添加它; 当选择器命名一个setter时,使用dynamic-setter方法添加它.

那么dynamic-getter和-setter方法如何工作呢?他们需要知道动态获取和设置什么属性,但是他们还需要不带参数(getter)或一个参数(setter,它取值),以匹配原始的属性访问消息.您可能想知道这些通用实现如何知道要获取或设置的属性.答案是:它在选择器中!用于发送消息的选择器作为隐藏参数传递给实现_cmd,因此以与以前相同的方式检查该选择器以提取应动态获取或设置的属性的名称.然后,动态getter应该发送[data objectForKey:keyExtractedFromSelector],动态setter应该发送[data setObject:newValue forKey:keyExtractedFromSelector].

两个警告:

  1. 当您使用property-access语法访问尚未在类中声明的"属性"时,您仍可能会收到编译器的投诉@interface.这是正常的和有意的; 你真的应该使用属性访问语法来访问已知的形式属性.你在做什么,虽然我发现解决它很有趣,但从技术上来说是滥用属性访问语法.
  2. 这仅适用于对象值.KVC对原始值进行装箱和拆箱,例如整数; 由于KVC没有参与,没有免费拳击和拆箱.如果您已声明正式属性(请参阅1),则需要使用Objective-C运行时API对它们进行内省,并自行完成装箱和拆箱.

  • ......这看起来很有趣,所以我继续做下去了:https://github.com/davedelong/Demos (3认同)
  • 如果你不想经常计算属性名称来自`_cmd`,你可以事先计算它,在块中捕获它,然后使用`imp_implementationWithBlock`将块转换为`IMP`.(iOS 4.3+或使用PLBlockImp) (2认同)

Dav*_*ong 6

这激起了我的好奇心,所以我继续使用Peter Hosey建议的压倒一切+resolveInstanceMethod:来产生吸气剂和制定者.我将结果对象(DDDynamicStorageObject)发布到github存储库:

https://github.com/davedelong/Demos