在Objective-C中在运行时确定赋值的接收者

时间:2013-09-09 07:45:30

标签: ios objective-c c

假设我有一个包含2个属性的类:

@interface MyClass ()

@property (strong, nonatomic) NSString *strA;
@property (strong, nonatomic) NSString *strB;

@end

在该类的某个地方,我有一个方法应该为这些属性中的一个赋值。问题是 - 属性将在运行时确定。我该怎么做呢?我想在没有代码复制的情况下这样做(可能是一个非常复杂的方法)。例如,这很糟糕:

- (void) mutateProperty:(BOOL)assignToA
{
   if (assignToA)
   {
       self.strA = @"newStr";
   }
   else
   {
       self.strB = @"newStr";
   }
}

我希望能够完成类似的事情:

- (void) mutateProperty:(BOOL)assignToA
{
   NSString *propertyToUse = nil;
   if (assignToA)
   {
       propertyToUse = self.strA;
   }
   else
   {
       propertyToUse = self.strB;
   }

   propertyToUse = @"newStr" //But this will only change the propertyToUse variable's value and not affect the scope outside the method.
}

1 个答案:

答案 0 :(得分:2)

发布的代码不是作业,而是发送给自己的消息:

self.strA = @"newStr";

真的是

[self setStrA:@"newStr"];

(如果您为属性声明了自定义setter,方法名称可能会有所不同。)

所以你的问题是关于调度方法。有许多方法可以做到这一点,所有方法都有细节不同。然而对于你的情况,代码中只有一个点,你只选择两个选项,我会选择你已经发布的简单条件。它最易读,代码重复很少。

如果您的案例比发布的代码更复杂,您可能希望使用一些不同的派遣方式。

在Objective-C中分派的最基本方法是手动计算选择器:

SEL selector = NULL;
switch (status) {
    case 1:
        selector = @selector(setStrA:);
        break;
    case 2:
        selector = @selector(setStrB:);
        break;
    case 3:
        selector = @selector(setStrC:);
        break;
}
[self performSelector:selector withObject:@"newStr"];

由于ARC无法使用选择器的名称来确定参数和返回类型所有权,因此不能与ARC一起使用。你必须使编译器警告静音,这很难看。

正如nielsbot所指出的,设置任意属性的内置方法是KVC:您可以计算KVC用来查找匹配方法的“密钥”:

NSString *key = nil;
switch (status) {
    case 1:
        key = @"strA";
        break;
    case 2:
        key = @"strB";
        break;
    case 3:
        key = @"strC";
        break;
}
[self setValue:@"newStr" forKey:key];

这有点开销,但它也适用于POD参数类型。