What's required to implement root class of Objective-C?

99封情书 提交于 2019-12-03 15:24:50

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.

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.

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);
}

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.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!