如何从ARC下的运行时定义的类方法中返回结构值? [英] How do I return a struct value from a runtime-defined class method under ARC?

查看:87
本文介绍了如何从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_msgSendobjc_msgSend_stretobjc_msgSendSuperobjc_msgSendSuper_stret之一的调用. [...]具有数据结构作为返回值的方法是使用objc_msgSendSuper_stretobjc_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, or objc_msgSendSuper_stret. [...] Methods that have data structures as return values are sent using objc_msgSendSuper_stret and objc_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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆