实现 Objective-C 的根类需要什么?

发布于 2024-09-16 02:05:45 字数 1065 浏览 10 评论 0原文

我尝试了这段代码:

// main.m
#import <stdio.h>

@interface Test 
+ (void)test;
@end
@implementation Test
+ (void)test
{
    printf("test");
}
@end

int main()
{
    [Test test];
    return  0;
}

使用没有任何框架的 LLVM/Clang,编译时不会出现此错误:

Undefined symbols:
  "_objc_msgSend", referenced from:
      _main in main.o
ld: symbol(s) not found
clang: error: linker command failed with exit code 1 (use -v to see invocation)

所以我添加了 libobjc.dylib。代码已编译,但引发了此运行时异常:

objc[13896]: Test: Does not recognize selector forward::
Program received signal:  “EXC_BAD_INSTRUCTION”.

#0  0x9932a4b4 in _objc_error
#1  0x9932a4ea in __objc_error
#2  0x993212b6 in _objc_msgForward
#3  0x99321299 in _objc_msgForward
#4  0x99321510 in _class_initialize
#5  0x99328972 in prepareForMethodLookup
#6  0x99329c17 in lookUpMethod
#7  0x99321367 in _class_lookupMethodAndLoadCache
#8  0x99320f13 in objc_msgSend
#9  0x00001ee5 in start

我意识到根类需要一些实现,但我不知道下一步应该做什么。创建新的根类需要什么?对此有什么规范吗?

I tried this code:

// main.m
#import <stdio.h>

@interface Test 
+ (void)test;
@end
@implementation Test
+ (void)test
{
    printf("test");
}
@end

int main()
{
    [Test test];
    return  0;
}

with LLVM/Clang without any framework, it doesn't compiled with this error:

Undefined symbols:
  "_objc_msgSend", referenced from:
      _main in main.o
ld: symbol(s) not found
clang: error: linker command failed with exit code 1 (use -v to see invocation)

So I added libobjc.dylib. Code compiled, but threw this runtime exception:

objc[13896]: Test: Does not recognize selector forward::
Program received signal:  “EXC_BAD_INSTRUCTION”.

#0  0x9932a4b4 in _objc_error
#1  0x9932a4ea in __objc_error
#2  0x993212b6 in _objc_msgForward
#3  0x99321299 in _objc_msgForward
#4  0x99321510 in _class_initialize
#5  0x99328972 in prepareForMethodLookup
#6  0x99329c17 in lookUpMethod
#7  0x99321367 in _class_lookupMethodAndLoadCache
#8  0x99320f13 in objc_msgSend
#9  0x00001ee5 in start

I realized some implementation required for root class, but I don't know what should I do next. What's required to make a new root class? And is there any specification for this?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

岁月流歌 2024-09-23 02:05:45

我刚刚提出这个问题是因为我有同样的“学术”问题。经过一番研究后,我发现这个问题的其他答案并不完全正确。

确实,在 Apple Objective-C 2.0 运行时上,您必须实现某些方法才能使代码正常工作。实际上您只需要实现一个方法:类方法initialize

@interface MyBase 
+ (void)test;
@end
@implementation MyBase
+ (void)initialize {}
+ (void)test {
 // whatever
}
@end

当您第一次使用您的类时,运行时将自动调用 initialize (如Apple 文档)。没有实现这个方法是导致消息转发错误的原因。

使用clang test.m -Wall -lobjc(或gcc)编译将允许您毫无问题地调用类方法测试。让对象分配工作是另一回事。如果您使用实例变量,至少,您的基类上需要一个 isa 指针。运行时期望它存在。

I just came to this question because I had the same "academic" question. After working through it a bit, I have found that the other answers to this question aren't completely correct.

It is true that on the Apple Objective-C 2.0 runtime, you must implement certain methods in order for your code to work. There is actually only one method that you need to implement: the class method initialize.

@interface MyBase 
+ (void)test;
@end
@implementation MyBase
+ (void)initialize {}
+ (void)test {
 // whatever
}
@end

The runtime will automatically call initialize when you first use your class (as explained in Apple's documentation). Not implementing this method is the reason for the message forwarding error.

Compiling with clang test.m -Wall -lobjc (or gcc) will allow you to call the class method test without any issue. Making object allocation work is a different story. At the very least, you'll need an isa pointer on your base class if you're using instance variables. The runtime expects this to be there.

挽心 2024-09-23 02:05:45

在 Apple 运行时,最低规范很容易解释:您必须实现 NSObject 协议中的每个方法。请参阅 此处。这绝对是不平凡的。您可能需要添加一些附加函数,例如 +alloc 以便能够创建实例等。Apple 的所有框架中只有两个公共根类: < code>NSObjectNSProxy。实际上,完全没有理由创建根类。我不确定 Apple 是否有关于此问题的任何文档。

在实践中,您要做的是继承 NSObjectNSProxy 并在它们之上构建。如果执行以下操作,您的代码将起作用:

@interface Test : NSObject
+ (void)test;
@end

正如 Tilo 指出的,在 GNU 运行时等其他运行时上情况并非如此。

On the Apple runtime, the minimum specs are pretty easily explained: You have to implement every method in the NSObject protocol. See here. This is absolutely non-trivial. You might want to add a couple of additional functions like +alloc in order to be able to create an instance, etc. There are only two public root classes in all of Apple's frameworks: NSObject and NSProxy. In practice, there is absolutely no reason to create a root class. I'm not sure there is any documentation to this issue by Apple.

What you will do in practice is to inherit from NSObject or NSProxy and build on top of them. Your code will work if you do the following:

@interface Test : NSObject
+ (void)test;
@end

As Tilo pointed out, this is not the case on other runtimes like the GNU runtime.

喜你已久 2024-09-23 02:05:45

在我的系统(Linux + GCC 上的 GNUstep)中,我必须用以下方法替换上面的分配方法,以使示例正常工作。我认为这是由于较新的 obj-c 运行时(此处的运行时文档:Objective-C 运行时参考

+ alloc
{
  return (id)class_createInstance(self, 0);
}

In my system (GNUstep on linux + GCC) I had to replace the above alloc method with the following, to make the sample work. I think this is due to a newer obj-c runtime (documentation of the runtime here: Objective-C Runtime Reference from the Mac Developer Library.

+ alloc
{
  return (id)class_createInstance(self, 0);
}
时光沙漏 2024-09-23 02:05:45

上面的例子可以用 gcc 和 GNU-runtime 很好地编译。在 Objective-C 中,通常任何类只要没有超类就可以成为根类。如果 Apple 运行时需要不同的东西,那么它是特定于运行时的。

此外,根类还有一些特定的东西:

所有实例方法也是具有相同实现的类方法(如果没有明确实现)。以下应用程序的输出:

#import <stdio.h>

@interface Test
+ alloc;
+ (void)test;
- (void)test;
- (void)otherTest;
@end
@implementation Test
+ alloc
{
  return (id)class_create_instance(self);
}

+ (void)test
{
    printf("class test\n");
}

- (void)test
{
    printf("instance test\n");
}

- (void)otherTest
{
    printf("otherTest\n");
}
@end

int main()
{
    id t = [Test alloc];
    [Test test];
    [t test];
    [Test otherTest];
    [t otherTest];
    return  0;
}

将是:

class test
instance test
otherTest
otherTest

创建新根类最难的部分是 +alloc-dealloc 但如我的示例中所示,运行时(在我的例子是 GNU 运行时)可以做到这一点。但我不知道运行时分配是否足够好。我知道一些基金会使用自己的分配机制来隐藏对象结构中的引用计数器。我不知道苹果是否也这样做,以及他们的运行时是否已经处理好它。

The above example compiles fine with gcc and GNU-runtime. In Objective-C normally any class can be a root class by simply not having a super class. If the Apple-runtime requires something different, then it's runtime specific.

Additionally there is something specific with root classes:

All instance methods are also class methods with the same implementation (if not explicitly implemented otherwise). The output of the following app:

#import <stdio.h>

@interface Test
+ alloc;
+ (void)test;
- (void)test;
- (void)otherTest;
@end
@implementation Test
+ alloc
{
  return (id)class_create_instance(self);
}

+ (void)test
{
    printf("class test\n");
}

- (void)test
{
    printf("instance test\n");
}

- (void)otherTest
{
    printf("otherTest\n");
}
@end

int main()
{
    id t = [Test alloc];
    [Test test];
    [t test];
    [Test otherTest];
    [t otherTest];
    return  0;
}

would be:

class test
instance test
otherTest
otherTest

The hardest part on creating a new root class is the +alloc and -dealloc but as seen in my example the runtime (in my case the GNU-runtime) can do this. But I don't know if the runtime allocation is good enough. I know that some foundations use an own allocation mechanism to hide the reference counter from the object structure. I don't know if Apple does this too and if their runtime already takes care of it.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文