Как создать CKComponentViewAttribute для метода с несколькими аргументами

Я хочу создать компонент для подкласса UIButton. Чтобы настроить кнопку, я хочу установить изображение. Моя проблема в том, что я не знаю, как создать CKComponentViewAttribute, который принимает два аргумента, необходимые для метода UIButton setImage:forState:,

Я попробовал это:

[CKComponent newWithView:{
  [KGHitTestingButton class],
  {
    {CKComponentActionAttribute(@selector(onMenuTap))},
    {@selector(setImage:forState:), [UIImage imageNamed:@"location_action"]}, @(UIControlStateNormal)},
             }
  } size:{.width = 30, .height = 30}]

Но это не скомпилируется. То же самое с этой версией:

    {@selector(setImage:forState:), @[[UIImage imageNamed:@"location_action"]}, @(UIControlStateNormal)]},
             }

Я прочитал здесь http://componentkit.org/docs/advanced-views.html что мне нужно объединить свои входные данные в один объект. Как мне это сделать в этом случае?

Обновление: я нашел следующую подсказку здесь https://github.com/facebook/componentkit/issues/265:

"CKComponentViewAttribute может быть инициализирован произвольным блоком. Вот пример:

static const CKComponentViewAttribute titleShadowColorAttribute = {"MyComponent.titleShadowColor", ^(UIButton *button, id value){
  [button setTitleShadowColor:value forState:UIControlStateNormal];
}};

"

И вот как мне наконец удалось решить мою проблему:

static const CKComponentViewAttribute imageAttribute = {"LocationActionButton.imageAttribute", ^(UIButton *button, id value){
    [button setImage:value forState:UIControlStateNormal];
}};
CKComponent *locationActionButton = [CKComponent newWithView:{
    [UIButton class],
    {
        {@selector(setBackgroundColor:), [UIColor redColor]},
        {imageAttribute, [UIImage imageNamed:@"location_action"]}
    }
} size:{.width = 30, .height = 30}];

Вы можете сделать это встроенным, чтобы сделать его короче:

CKComponent *locationActionButton = [CKComponent newWithView:{
    [UIButton class],
    {
        {@selector(setBackgroundColor:), [UIColor redColor]},
        {{"LocationActionButton.imageAttribute", ^(UIButton *button, id value){
            [button setImage:value forState:UIControlStateNormal];
        }}, [UIImage imageNamed:@"location_action"]}
    }
} size:{.width = 30, .height = 30}];

2 ответа

Решение

Один из способов решить эту проблему - создать закрытую категорию для класса, который передает коллекцию с аргументами, а затем применяет ее, как и ожидалось. Так что-то вроде:

@interface KGHitTestingButton (CKPrivate)
- (void)_ckSetImageforState:(NSArray*)args;
@end
@implementation
- (void)_ckSetImageforState:(NSArray*)args {
    [self setImage:args[0] forState:[args[1] integerValue]];
}
@end

...

[CKComponent newWithView:{
      [KGHitTestingButton class],   
      {
          {@selector(_ckSetImageforState:), @[[UIImage imageNamed:@"location_action"]}, @(UIControlStateNormal)]},
         }
 ...

Это не красиво, но это обойдет это ограничение. NSDictionary будет альтернативой, но потребует определения некоторых статических ключей.

CKComponentViewAttribute имеет 2 инициализатора. Один с селектором, самый распространенный метод, который мы используем.

CKComponentViewAttribute(SEL setter);
// e.g. ' { @selector(setBackgroundColor:), color} '

Другой

CKComponentViewAttribute(const std::string &ident,
                       void (^app)(id view, id value),
                       void (^unapp)(id view, id value) = nil,
                       void (^upd)(id view, id oldValue, id newValue) = nil) ;

требуется идентификатор и 3 блока для настройки просмотра в различных условиях. Ссылка больше форма CKComponentViewAttribute.h, а также "CKComponentGestureActions.h" например.

Как и в вашем случае:

{ {"setImage",
   ^(UIButton *button, id value) {
     [button setImage:theImageObject forState:UIControlStateNormal]
  },
 @0 // Bogus value, we don't use it.
}
Другие вопросы по тегам