Передача CGColorRef в качестве значения в KVC / KVO

#iphone #quartz-graphics #opacity #key-value-observing #key-value-coding

#iPhone #quartz-графика #непрозрачность #наблюдение за ключом-значением #кодирование ключа-значения

Вопрос:

Я использую непрозрачность для создания всех моих иллюстраций Quartz2D, и сейчас я решаю проблему изменения цветов с помощью KVC / KVO. Opacity определяет все свои цветовые переменные как @dynamic и реализует свои собственные средства доступа как часть определения класса.

Мой вопрос в том, как мне передать новое значение CGColorRef по значению ключа?

Пока (в качестве тестового стенда) Я зашел так далеко:

 // Testbed ... Testbed ... Testbed ... Testbed ... Testbed ... Testbed ... Testbed ...
      CGColorSpaceRef space = CGColorSpaceCreateDeviceRGB();
      CGFloat components[4] = {1.0f, 1.0f, 1.0f, 1.0f};
      CGColorRef color = CGColorCreate(space, components);

      [myCALayerReceiverObject setValue: color forKey: @"numColour"];
// Testbed ... Testbed ... Testbed ... Testbed ... Testbed ... Testbed ... Testbed ...
  

Цветовое пространство и код создания извлекаются непосредственно из генератора классов CALayer от Opacity (я еще не настолько продвинут), но передача ‘color’ в качестве значения приводит к сбою симулятора iPhone, и XCode выдает мне очень загадочное предупреждение;

«Несовместимые типы указателей отправляют ‘CGColorRef’ (он же struct ‘CGColor *’) параметру типа ‘id’ «.

Как мне преобразовать CGColorRef, чтобы передать его через KVC получателю? Заранее спасибо.

Ответ №1:

Приведение CGColorRef к (id) работает. Вот пример настройки цвета тени на черный:

 [layer setValue:(id)[UIColor blackColor].CGColor forKey:@"shadowColor"];
  

Ответ №2:

Я собирался предложить использовать NSValue для переноса вашего цветового объекта, но во время тестирования я пришел к выводу, что KVO / KVC не будет работать с CGColors. Согласно Руководству по программированию кодирования ключ-значение, примитивные типы и структуры переносятся с использованием NSValue или NSNumber. Однако при попытке получить доступ к CGColorRef свойству я получаю исключение «не соответствует KVC». Кажется, что указатели на структуры не переносятся в NSValues таким же образом, как сами структуры. Вот мой тестовый код:

 @interface MyClass : NSObject {
    CGColorRef color;
}
@property (assign) CGColorRef color;
@end

@implementation MyClass
- (CGColorRef)color { return color; }
- (void)setColor:(CGColorRef)newColor { color = newColor; }
@end

int main(int argc, char **argv) {
    NSAutoreleasePool *p = [NSAutoreleasePool new];
    MyClass *theObject = [MyClass new];
    CGColorRef theColor = CGColorCreateGenericRGB(1.0,1.0,1.0,1.0);
    theObject.color = theColor; // works
    NSLog(@"%@",[theObject valueForKey:@"color"]); // NSValue expected, actually causes exception
    [p release];
    return 0;
}
  

Одним из возможных обходных путей является добавление категории в соответствующий класс, который определяет средства доступа для другого ключа. Эти средства доступа будут оболочками NSValue для numColour ключа.

 // in the category
- (NSValue *)numColourKVC {
    return [NSValue valueWithPointer:(void*)self.numColour];
}
- (void)setNumColourKVC:(NSValue *)newValue {
    self.numColour = (CGColorRef)[newValue pointerValue];
}
  

Затем вы должны установить цвет на своем тестовом стенде следующим образом:

 [myCALayerReceiverObject setValue:[NSValue valueWithPointer:(void*)color] forKey:@"numColourKVC"];
  

Комментарии:

1. Я только что заметил, CGColorCreateGenericRGB недопустимо для iOS, поэтому мой тестовый код будет работать только для OS X. На самом деле не имеет значения, откуда берется цвет, поскольку это не проблема.

2. Спасибо вам за это ughoavgfhw. С момента публикации вопроса я поддерживал связь с Opacity, и причина, по которой мой код вообще не работал, заключается в небольшом упущении в логике Opacity, которая создает подклассы CALayer. На самом деле, то, что я пытался сделать изначально, правильно, и разработчик Opacity исправит упущение в будущей версии модуля. Спасибо за вашу помощь.

3. но CGColor не является скаляром или структурой. это объект Core Foundation

Ответ №3:

Ошибка не требует пояснений — вам нужно привести свой CGColorRef как (id) . С моей точки зрения, это должно сработать:

 [myCALayerReceiverObject setValue: (id)color forKey: @"numColour"];
  

Комментарии:

1. Говорить, что ошибка «не требует пояснений», бесполезно. Что является позором, поскольку ваш ответ был в конечном итоге полезным и правильным.