1

我正在编写用于从 python 访问目标 c 的库,所以我使用 Cython 和目标 c 运行时来访问目标 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 这样的函数,getter 和 setter 根本不会被调用,结果我得到的是空指针。

有谁知道如何调用get/set funcs。来自目标 c 运行时的动态属性?

谢谢!

4

2 回答 2

4

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

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

@NathanDay 使用 KVC 的方法是一种不错的方法,但[obj valueForKey:@"foo"][obj foo]. 不过,它很接近。

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

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

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

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

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

于 2013-07-29T15:01:50.083 回答
2

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

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

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

您也可以像调用其他方法一样调用属性 setter 和 getter,因此您可以使用所有可以与常规方法一起使用的动态方法调用功能,您可能已经解决了这个问题。

于 2013-07-29T13:41:36.827 回答