如何在observeValueForKey中优化这个巨大的if / else if块

时间:2015-10-14 21:02:52

标签: objective-c nsdictionary key-value-observing foundation

我有一个控制器,它注册为视图上很多属性的观察者。这是我们的-observeValueForKeyPath::::方法:

-(void)observeValueForKeyPath:(NSString *)keyPath
                     ofObject:(id)object
                       change:(NSDictionary *)change
                      context:(void*)context
{

   if( context == kStrokeColorWellChangedContext )
   {
      [self setValue:[change objectForKey:NSKeyValueChangeNewKey] forKey:kStrokeColorProperty];
   }
   else if( context == kFillColorWellChangedContext )
   {
      [self setValue:[change objectForKey:NSKeyValueChangeNewKey] forKey:kFillColorProperty];
   }
   else if( context == kBodyStyleNumChangedContext )
   {
      [self setValue:[change objectForKey:NSKeyValueChangeNewKey] forKey:kBodyStyleNumProperty];
   }
   else if( context == kStyleChangedContext )
   {
      [self setValue:[change objectForKey:NSKeyValueChangeNewKey] forKey:kStyleProperty];
   }
   else if( context == kStepStyleChangedContext )
   {
      [self setValue:[change objectForKey:NSKeyValueChangeNewKey] forKey:kStepStyleProperty];
   }
   else if( context == kFirstHeadStyleChangedContext )
   {
      [self setValue:[change objectForKey:NSKeyValueChangeNewKey] forKey:kFirstHeadStyleProperty];
   }
   else if( context == kSecondHeadStyleChangedContext )
   {
      [self setValue:[change objectForKey:NSKeyValueChangeNewKey] forKey:kSecondHeadStyleProperty];
   }

实际上,这些else if陈述中约有3倍多。{ 您可以看到的一件事是每个块具有相同的代码,这使我认为可以优化它。

我最初的想法是让NSDictionary调用keyPathForContextDictionary,其中键是Context后缀(类型为void*)的常量,值为适当的字符串常量,由Property后缀

表示

然后这个方法只需要一行:

[self setValue:[change objectForKey:NSKeyValueChangeNewKey] forKey:keyPathForContextDictionary[context]];

请注意,我需要使用某种数据结构来识别要使用的keyPath,并且我不能简单地使用传递给方法的keyPath参数。这是因为有多个视图具有我观察到的相同属性(例如,颜色孔具有color属性)。因此,每个视图都需要确定一个唯一的密钥路径,该密钥路径当前是根据上下文确定的

问题在于您无法在void*中使用NSDictionary作为键。那么......有没有人对我能做什么有任何建议?

编辑: 以下是定义常量的示例:

void * const kStrokeColorWellChangedContext = (void*)&kStrokeColorWellChangedContext;
void * const kFillColorWellChangedContext = (void*)&kFillColorWellChangedContext;
void * const kBodyStyleNumChangedContext = (void*)&kBodyStyleNumChangedContext;
void * const kStyleChangedContext = (void*)&kStyleChangedContext;

NSString *const kStrokeColorProperty     = @"strokeColor";
NSString *const kFillColorProperty       = @"fillColor";
NSString *const kShadowProperty          = @"shadow";
NSString *const kBodyStyleNumProperty    = @"bodyStyleNum";
NSString *const kStyleProperty           = @"style";

2 个答案:

答案 0 :(得分:1)

类型void *并不是一个你需要匹配的类型,因为它是“通用指针”。它精确地用于context参数,以便您可以使用任何您喜欢的基础类型,包括对象类型。你所要做的就是进行适当的演员表。

因此,您可以非常轻松地将kTHINGYChangedContext更改为NSString或您喜欢的任何其他对象,然后将其用作上下文中的键 - >键路径映射。

开始于:

NSString * const kStrokeColorWellChangedContext = @"StrokeColorWellChangedContext";

当您注册观察时,您必须执行桥接演员:

[colorWell addObserver:self
            forKeyPath:keyPath
               options:options
               context:(__bridge void *)kStrokeColorWellChangedContext];

然后当观察发生时,你进行反向投射:

-(void)observeValueForKeyPath:(NSString *)keyPath
                     ofObject:(id)object
                       change:(NSDictionary *)change
                      context:(void*)ctx
{
    NSString * context = (__bridge NSString *)ctx;
    // Use context, not ctx, from here on.
}

然后从那里继续进行密钥路径查找。

答案 1 :(得分:1)

Josh Caswell有一个很好的答案,但我不想将我们的常量类型修改为NSStrings*

相反,解决方法是将void*转换为NSValues w / -valueWithPointer。这样我就可以在我的词典中使用void*作为键

以下是代码:

   NSString *toolKeyPath = [[ToolController keyPathFromContextDictionary] objectForKey:[NSValue valueWithPointer:context]];

   if( toolKeyPath )
   {
      if( [change objectForKey:NSKeyValueChangeNewKey] == (id)[NSNull null] )
      {
         [self setValue:nil forKey:toolKeyPath];
      }
      else
      {
         [self setValue:[change objectForKey:NSKeyValueChangeNewKey] forKey:toolKeyPath];
      }
   }

字典:

+(NSDictionary*) keyPathFromContextDictionary
{
   return @{
             [NSValue valueWithPointer:kStrokeColorWellChangedContext] : kStrokeColorProperty,
             [NSValue valueWithPointer:kFillColorWellChangedContext] : kFillColorProperty,
             [NSValue valueWithPointer:kBodyStyleNumChangedContext] : kBodyStyleNumProperty,
             [NSValue valueWithPointer:kStyleChangedContext] : kStyleProperty,
             [NSValue valueWithPointer:kStepStyleChangedContext] : kStepStyleProperty,
             [NSValue valueWithPointer:kFirstHeadStyleChangedContext] : kFirstHeadStyleProperty,
             [NSValue valueWithPointer:kSecondHeadStyleChangedContext] : kSecondHeadStyleProperty,
             [NSValue valueWithPointer:kShadowChangedContext] : kShadowProperty,
             [NSValue valueWithPointer:kStrokeWidthChangedContext] : kStrokeWidthProperty,
             [NSValue valueWithPointer:kBlurRadiusChangedContext] : kBlurRadiusProperty,
             [NSValue valueWithPointer:kFontSizeChangedContext] : kFontSizeProperty
         };
}