我正在编写用于从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的动态属性?
谢谢!
答案 0 :(得分:3)
正确调用getter和setter。但是,我需要从目标c运行时设置并获取此动态属性的值,因此如果我使用像objc_getIvar / objc_setIvar这样的函数,则根本不会调用getters和setter,并且我得到空指针作为结果。
这是你的错。您不应该调用objc_getIvar
或objc_setIvar
来与其他对象属性进行交互。属性不是ivars。属性是实现方法的承诺。您不能假设这些方法是如何实现的。您当然不能认为它们等同于对objc_getIvar
的调用(正如您所发现的那样)。
[obj valueForKey:@"foo"]
与[obj foo]
不完全相同。它仍然很接近。
首先,要明确的是,你并没有真正“获得对象属性的价值”。你甚至没有真正“调用对象方法”。您将消息发送到对象并返回结果。属性通常是一种方便的方式来声明您将响应某些消息(选择器)。
要正确发送消息,您必须致电objc_msgSend
。请注意,它有几种形式,具体取决于返回值是浮点还是结构(这是使用valueForKey:
的好处;它使所有返回值看起来都相同而且您不需要知道要调用哪种形式的objc_msgSend
。在任何情况下,您都需要知道如何解释返回值,因为它可能是id
或它可能是标量。
我不相信在最常见的情况下可以在运行时确定选择器的返回类型(例如,如果类实现forwardingTargetForSelector:
)。你真的应该在编译时从头文件中获取这些信息。但在大多数情况下,您可以使用class_getProperty
和property_getAttributes
或class_getInstanceMethod
和method_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,因此您可以使用所有可以使用常规方法的动态方法调用功能,您可能已经认识到这一点。