2014-02-04 2 views
3

Контекст: У меня есть несколько CGPathRef в пользовательском классе, полученном из NSObject, с именем model. Я ищу способ вернуть определенный CGPathRef, основанный на строке, которую я генерирую во время выполнения.Как я могу получить доступ к свойствам, не совместимым с KVC, только с их именем?

Упрощенный пример, если я мог бы использовать KVC:

#model.h 
@property (nonatomic) CGMutablePathRef pathForwardTo1; 
@property (nonatomic) CGMutablePathRef pathForwardTo2; 
@property (nonatomic) CGMutablePathRef pathForwardTo3; 
... 


#someVC.m 
-(void)animateFromOrigin:(int)origin toDestination:(int)destination{ 
    int difference = abs(origin - destination); 
     for (int x =1; x<difference; x++) { 
      NSString *pathName = [NSString stringWithFormat:@"pathForwardTo%d", x]; 
      id cgPathRefFromString = [self.model valueForKey:pathName]; 
      CGPathAddPath(animationPath, NULL, cgPathRefFromString); 
     } 
} 

Вопрос: Как я могу получить доступ к не-КЦУ совместимых свойств (CGPathRef) с только их именем, представленное в виде строки?

+0

Вы называете их «свойствами». Имеют ли они методы доступа? –

+0

Да, надеюсь, мое редактирование разъяснило это немного. Спасибо –

+0

Конечно, вы можете использовать ops 'performSelector' для вызова методов getter, но неясно, как вы возвращаете этот тип результата. Возможно, вам придется использовать 'methodForSelector', а затем вызывать реализацию« raw »метода, чего я никогда не пытался. –

ответ

2

Для этого вы должны использовать NSInvocation. Что-то вроде:

// Assuming you really need to use a string at runtime. Otherwise, hardcode the selector using @selector() 
SEL selector = NSSelectorFromString(@"pathForwardTo1"); 
NSMethodSignature *signature = [test methodSignatureForSelector:selector]; 
NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:signature]; 
[invocation setSelector:selector]; 
[invocation setTarget:test]; 
[invocation invoke]; 

CGMutablePathRef result = NULL; 
[invocation getReturnValue:&result]; 

Вы также можете сделать это прямо с правильным вариантом objc_msgSend, но NSInvocation легче (хотя, вероятно, значительно медленнее).

EDIT: Я положил простую небольшую тестовую программу here.

+0

Сотни раз медленнее. Но это обычно не является серьезной проблемой. Это по-прежнему очень полезный ответ. –

1

Это подробно обсуждалось на cocoa-dev. Короткий ответ: вы не можете напрямую.

Но часто оказывается, что вокруг есть много способов. В вашем конкретном примере вы должны хранить их в массиве, и тогда вам даже не понадобится вызов KVC.

Опять же, для вашего конкретного примера, еще одним возможным решением является переход на UIBezierPath, который может быть преобразован в CGPath, как вам нужно.

Как более общее решение, вы можете обернуть их в объект, который просто держит значение для вас, и KVC на , что. Это в основном то, как NSValue часто используется для обертывания необработанных указателей.

Полностью общее решение состоит в том, что вы можете реализовать valueForUndefinedKey:, осмотреть ключ и вернуть то, что хотите. Например, вы можете вставлять пути в массив и индексировать его на основе указанного ключа. Или вы могли бы вставлять их в словарь и искать их там (это в основном то, что делает CALayer). И, конечно, если вам действительно нужно, чтобы он был динамичным, вы могли бы заглянуть во время выполнения и в основном переобучить KVC ... было бы очень редко, что это был бы правильный ответ. Практически все эти «родовые» решения являются чрезмерными для большинства проблем.

Короткий ответ заключается в том, что KVC не всегда хорошо работает с объектами низкого уровня, которые не являются бесплатными мостами.

0

Что бы я сделал (и иногда делаю) это обернуть CGPathRef в UIBezierPath точно так, что является объектом и имеют все преимущества, получаемые с ним, в том числе КЦА, способность придерживаться его в NSArray или NSDictionary , и управление памятью ARC. В конце концов, это именно то, что UIBezierPath - (более или менее).

+1

Следует также отметить, что Apple специально [рекомендует] (https://developer.apple.com/library/ios/documentation/2ddrawing/conceptual/drawingprintingios/GraphicsDrawingOverview/GraphicsDrawingOverview.html#//apple_ref/doc/uid/TP40010156 -CH14-SW20), используя UIBezierPath для * создания * путей в пользу CGPath, если вам действительно не нужны определенные функции CoreGraphics, которые UIBezierPath не раскрывает. –

Смежные вопросы