如何从ARC下的运行时定义的类方法中返回结构值? [英] How do I return a struct value from a runtime-defined class method under ARC?
问题描述
我有一个返回CGSize
的类方法,我想通过Objective-C运行时函数调用它,因为我将类和方法的名称指定为字符串值.
I have a class method returning a CGSize
and I'd like to call it via the Objective-C runtime functions because I'm given the class and method names as string values.
我正在XCode 4.2中使用ARC标志进行编译.
I'm compiling with ARC flags in XCode 4.2.
方法签名:
+(CGSize)contentSize:(NSString *)text;
我尝试做的第一件事是像这样用objc_msgSend
调用它:
The first thing I tried was to invoke it with objc_msgSend
like this:
Class clazz = NSClassFromString(@"someClassName);
SEL method = NSSelectorFromString(@"contentSize:");
id result = objc_msgSend(clazz, method, text);
此操作因"EXC_BAD_ACCESS"而崩溃,并且没有堆栈跟踪.我之所以首先使用它,是因为objc_msgSend
的文档说,
This crashed with "EXC_BAD_ACCESS" and without a stack trace. I used this first because the documentation for objc_msgSend
says,
当遇到方法调用时,编译器会生成对函数
objc_msgSend
,objc_msgSend_stret
,objc_msgSendSuper
或objc_msgSendSuper_stret
之一的调用. [...]具有数据结构作为返回值的方法是使用objc_msgSendSuper_stret
和objc_msgSend_stret
发送的.
When it encounters a method call, the compiler generates a call to one of the functions
objc_msgSend
,objc_msgSend_stret
,objc_msgSendSuper
, orobjc_msgSendSuper_stret
. [...] Methods that have data structures as return values are sent usingobjc_msgSendSuper_stret
andobjc_msgSend_stret
.
接下来,我像这样使用objc_msgSend_stret
:
Next, I used objc_msgSend_stret
like this:
Class clazz = NSClassFromString(@"someClassName);
SEL method = NSSelectorFromString(@"contentSize:");
CGSize size = CGSizeMake(0, 0);
objc_msgSend_stret(&size, clazz, method, text);
使用上述签名会给我带来以下两个编译器错误和两个警告:
Using the above signature gives me the following two compiler errors and two warnings:
错误:自动引用计数问题:ARC不允许将非客观C指针类型'CGSize *'(aka'struct CGSize *')隐式转换为'id'
error: Automatic Reference Counting Issue: Implicit conversion of a non-Objective-C pointer type 'CGSize *' (aka 'struct CGSize *') to 'id' is disallowed with ARC
警告:语义问题:不兼容的指针类型将"CGSize *"(也称为"struct CGSize *")传递给类型为"id"的参数
warning: Semantic Issue: Incompatible pointer types passing 'CGSize *' (aka 'struct CGSize *') to parameter of type 'id'
错误:自动引用计数问题:ARC不允许将Objective-C指针隐式转换为'SEL'
error: Automatic Reference Counting Issue: Implicit conversion of an Objective-C pointer to 'SEL' is disallowed with ARC
警告:语义问题:不兼容的指针类型传递 参数类型为'SEL'的'__unsafe_unretained Class'
warning: Semantic Issue: Incompatible pointer types passing '__unsafe_unretained Class' to parameter of type 'SEL'
如果我看一下方法的声明,那就是:
If I look at the declaration of the method, it is:
OBJC_EXPORT void objc_msgSend_stret(id self, SEL op, ...)
__OSX_AVAILABLE_STARTING(__MAC_10_0, __IPHONE_2_0);
与objc_msgSend
相同:
OBJC_EXPORT id objc_msgSend(id self, SEL op, ...)
__OSX_AVAILABLE_STARTING(__MAC_10_0, __IPHONE_2_0);
这向我解释了编译器错误,但是在运行时级别使用什么来在运行时调用类及其静态方法并返回struct值?
This explains the compiler errors to me but what do I use at the run-time level to invoke a class and its static method at run-time and return a struct value?
推荐答案
您需要将objc_msgSend_stret
强制转换为正确的函数指针类型.它定义为void objc_msgSend_stret(id, SEL, ...)
,这实际上是不合适的类型.您将要使用类似的
You need to cast objc_msgSend_stret
to the correct function pointer type. It's defined as void objc_msgSend_stret(id, SEL, ...)
, which is an inappropriate type to actually call. You'll want to use something like
CGSize size = ((CGSize(*)(id, SEL, NSString*))objc_msgSend_stret)(clazz, @selector(contentSize:), text);
在这里,我们只是将objc_msgSend_stret转换为类型为(CGSize (*)(id, SEL, NSString*))
的函数,这是实现+contentSize:
的IMP
的实际类型.
Here we're just casting objc_msgSend_stret to a function of type (CGSize (*)(id, SEL, NSString*))
, which is the actual type of the IMP
that implements +contentSize:
.
请注意,我们还使用了@selector(contentSize:)
,因为没有理由对编译时已知的选择器使用NSSelectorFromString()
.
Note, we're also using @selector(contentSize:)
because there's no reason to use NSSelectorFromString()
for selectors known at compile-time.
还请注意,即使对于objc_msgSend()
的常规调用,也需要强制转换函数指针.即使直接调用objc_msgSend()
在您的特定情况下也可以工作,它还是基于这样的假设,即varargs方法调用ABI与调用非varargs方法的ABI相同,在所有平台上可能并非如此.
Also note that casting the function pointer is required even for regular invocations of objc_msgSend()
. Even if calling objc_msgSend()
directly works in your particular case, it's relying on the assumption that the varargs method invocation ABI is the same as the ABI for calling a non-varargs method, which may not be true on all platforms.
这篇关于如何从ARC下的运行时定义的类方法中返回结构值?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!