从目标c运行时调用目标c @dynamic属性的问题

时间:2013-07-29 13:02:27

标签: objective-c objective-c-runtime

我正在编写用于从python访问目标c的lib,所以我使用Cython和objective c runtime来访问目标c。让我们说用户以这种方式声明属性:

@property (assign) NSString *prop_nsstring_dyn;

他想在这个属性中使用@dynamic。好的,让我们使用这个宏:

#define ADD_DYNAMIC_PROPERTY(PROPERTY_TYPE, PROPERTY_NAME, SETTER_NAME) \
\
@dynamic prop_nsstring_dyn; \
- ( PROPERTY_TYPE ) PROPERTY_NAME \
{ \
printf("returning\n"); \
return ( PROPERTY_TYPE ) objc_getAssociatedObject(self, @selector(PROPERTY_NAME)); \
} \
\
- (void) SETTER_NAME :( PROPERTY_TYPE ) PROPERTY_NAME \
{ \
printf("setting\n"); \
objc_setAssociatedObject(self, @selector(PROPERTY_NAME), PROPERTY_NAME, OBJC_ASSOCIATION_RETAIN); \
} \

在此之后我们可以在@implementation中调用它:

ADD_DYNAMIC_PROPERTY(NSString*, prop_nsstring_dyn, setProp_nsstring_dyn);

如果我们以这种方式从目标c打电话:

c.prop_nsstring_dyn = @"test str";

c.prop_nsstring_dyn;

正确调用getter和setter。 但是,我需要从目标c运行时设置并获取此动态属性的值,因此如果我使用像objc_getIvar / objc_setIvar这样的函数,则根本不会调用getters和setter,并且我得到空指针作为结果。

有没有人知道如何调用get / set funcs。来自Objective c runtime的动态属性?

谢谢!

2 个答案:

答案 0 :(得分:3)

  

正确调用getter和setter。但是,我需要从目标c运行时设置并获取此动态属性的值,因此如果我使用像objc_getIvar / objc_setIvar这样的函数,则根本不会调用getters和setter,并且我得到空指针作为结果。

这是你的错。您不应该调用objc_getIvarobjc_setIvar来与其他对象属性进行交互。属性不是ivars。属性是实现方法的承诺。您不能假设这些方法是如何实现的。您当然不能认为它们等同于对objc_getIvar的调用(正如您所发现的那样)。

使用KVC的@ NathanDay方法是一种不错的方法,但[obj valueForKey:@"foo"][obj foo]不完全相同。它仍然很接近。

首先,要明确的是,你并没有真正“获得对象属性的价值”。你甚至没有真正“调用对象方法”。您将消息发送到对象并返回结果。属性通常是一种方便的方式来声明您将响应某些消息(选择器)。

要正确发送消息,您必须致电objc_msgSend。请注意,它有几种形式,具体取决于返回值是浮点还是结构(这是使用valueForKey:的好处;它使所有返回值看起来都相同而且您不需要知道要调用哪种形式的objc_msgSend。在任何情况下,您都需要知道如何解释返回值,因为它可能是id或它可能是标量。

我不相信在最常见的情况下可以在运行时确定选择器的返回类型(例如,如果类实现forwardingTargetForSelector:)。你真的应该在编译时从头文件中获取这些信息。但在大多数情况下,您可以使用class_getPropertyproperty_getAttributesclass_getInstanceMethodmethod_getReturnType在运行时确定返回值(您需要同时检查这两个值;开发人员没有规则)必须使用@property)声明“类似属性的东西”。

虽然可以将实际的C函数指针指向方法的实现,但通常不应该从对象外部执行此操作。 ObjC对象有许多方法可以处理不会转换为“使用该名称调用方法”的消息。你应该传递消息并让对象自己处理事情。

但是对于阅读和写作属性,Nathan的KVC方法可能就是您所需要的。不过,我真的建议你再看看PyObjC,因为他们已经解决了这些问题。至少,我会仔细研究他们的代码。

答案 1 :(得分:2)

您可以使用NSObject方法间接调用setter和getter方法

- [NSObject setValue:(id) forKey:(NSString *)];
- (id)[NSObject valueForKey:(NSString *)];

其中键是属性名称,如果属性是主要类型,如unsigned long,double等。那么setValue和value方法将处理NSNumber等价物。

此外,您可以像调用其他方法一样调用属性setter和getter,因此您可以使用所有可以使用常规方法的动态方法调用功能,您可能已经认识到这一点。