【问题标题】:Calling Objective-C method from imp从 imp 调用 Objective-C 方法
【发布时间】:2012-07-31 01:46:15
【问题描述】:

我试图在运行时获取一个方法,然后使用它的数据结构来调用它的实现。澄清一下,这是出于学习目的,而不是出于任何实际原因。所以这是我的代码。

#import <Foundation/Foundation.h>
#import <stdio.h>

#import <objc/runtime.h>

@interface Test : NSObject 
-(void)method;
@end

@implementation Test

-(void)method {
    puts("this is a method");
}

@end 

int main(int argc, char *argv[]) {

    struct objc_method *t = (struct objc_method*) class_getInstanceMethod([Test class], @selector(method));
    Test *ztest = [Test new];

    (t->method_imp)(ztest, t->method_name);

    [ztest release];
    return 0;
}

struct objc_method的定义如下(在objc/runtime.h中定义)

typedef struct objc_method *Method;

....

struct objc_method {
    SEL method_name                                          OBJC2_UNAVAILABLE;
    char *method_types                                       OBJC2_UNAVAILABLE;
    IMP method_imp                                           OBJC2_UNAVAILABLE;
}                                                            OBJC2_UNAVAILABLE;

但是,当我尝试编译我的代码时,我得到了这个错误。

error: dereferencing pointer to incomplete type

但是当我将它添加到我的代码中(以显式声明一个 objc_method)时,它会按预期工作。

struct objc_method {
    SEL method_name;
    char *method_types;
    IMP method_imp;
};

typedef struct objc_method* Method;

谁能向我解释为什么我的代码在我明确声明这个结构时有效,而不是当我从 objc/runtime.h 导入它时?它与 OBJC2_UNAVAILABLE 有什么关系吗?我找不到它的定义,但它是在我的环境中定义的。

编辑:

我运行gcc -E code.m -o out.m 来查看 OBJC2_UNAVAILABLE 被替换为什么,结果发现 OBJC2_UNAVAILABLE 在我的环境中被定义为 __attribute__((unavailable)) 。有人能解释一下这是什么意思吗?如果这个结构“不可用”,为什么Method 仍然有效?

【问题讨论】:

    标签: objective-c data-structures methods objective-c-runtime


    【解决方案1】:

    它的字段是之前定义的,但它在 ObjC-2 中是一个不透明的类型。改用运行时,不要自己定义字段:

    int main(int argc, char *argv[]) {
    
        Method t = class_getInstanceMethod([Test class], @selector(method));
        Test * ztest = [Test new];
    
        IMP imp = method_getImplementation(t);
    
        typedef void (*fn)(id,SEL);
        fn f = (fn)imp;
        f(ztest,@selector(method));
    
        [ztest release];
        return 0;
    }
    

    【讨论】:

    • 澄清一下,不透明的意思是结构定义在实现文件中而不是头文件中,对吗?
    • 在 c 结构的情况下,不透明意味着存在名称以供您使用指向其实例的句柄/指针,但其内容/字段对您(客户端)是隐藏的。这就像CFStringRef,您无法访问其中的字段,但您可以将它与 CFString API 一起使用。该句柄后面的内存可能是正式结构,也可能是 C++ 类型,或者实际上是由实现定义的任意内存 blob(并且很可能因版本而异)。你不能“看到”不透明的对象/类型/实例。
    • @JohnCorbett 谢谢 - 我完全同意 michael (+1) 是正确的答案。以我的为例。我省略了细节,因为当我发布示例时它们存在于他的答案中。
    【解决方案2】:

    我刚刚仔细查看了 objc 运行时标头,发现了问题所在,以及如何解决它:)

    因此,如果您查看包含结构的透明定义的文件区域,您会发现它位于以下内容的主体中:

    #if !__OBJC2__
    
    ...
    
    #endif
    

    既然定义了这个 IS,这意味着我们所指的结构实际上是前向声明的和不透明的(因此是不完整的)。

    我们必须做的是使用提供的函数来访问这些成员:

    IMP method_getImplementation(Method method);
    SEL method_getName(Method method);
    void method_getReturnType(Method method, char *dst, size_t dst_len);
    

    等等

    您可以在Runtime Reference Guide 中查看访问器方法的完整列表和许多其他好东西。

    希望对你有帮助!

    【讨论】:

      猜你喜欢
      • 2023-03-29
      • 2010-12-20
      • 1970-01-01
      • 2011-05-26
      • 1970-01-01
      • 2012-02-09
      • 1970-01-01
      • 2014-06-20
      • 2014-03-22
      相关资源
      最近更新 更多