2010-08-27 18 views
5

J'ai essayé ce code:Qu'est-ce qui est requis pour implémenter la classe racine d'Objective-C?

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

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

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

avec LLVM/Clang sans cadre, il n'a pas compilé avec cette erreur:

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) 

J'ajouté libobjc.dylib. Le code compilé, mais a lancé cette exception d'exécution:

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 

j'ai réalisé une mise en œuvre nécessaire pour la classe racine, mais je ne sais pas ce que dois-je faire. Qu'est-ce qui est requis pour créer une nouvelle classe racine? Et y a-t-il des spécifications pour cela?

+0

J'ai trouvé une ressource précieuse: http://code.google.com/p/ purefoundation/ Cependant, ne savent toujours pas sur les spécifications – Eonil

+0

juste pour référence ultérieure, la source d'exécution d'Apple objc source ouverte contient 'la source NSObject' trop – Eonil

Répondre

6

Je suis juste venu à cette question parce que j'avais la même question «académique». Après avoir travaillé un peu à travers, j'ai trouvé que les autres réponses à cette question ne sont pas complètement correctes.

Il est vrai que sur l'environnement d'exécution Apple Objective-C 2.0, vous devez implémenter certaines méthodes pour que votre code fonctionne.Il existe en réalité une seule méthode que vous devez implémenter: la méthode de classe initialize.

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

Le temps d'exécution appellera automatiquement initialize lorsque vous utilisez d'abord votre classe (comme expliqué in Apple's documentation). Ne pas implémenter cette méthode est la raison de l'erreur de transmission de message.

avec clang test.m -Wall -lobjc Compiler (ou gcc) vous permettra d'appeler le test de méthode de classe sans aucun problème. Faire fonctionner l'allocation d'objets est une histoire différente. À tout le moins, vous aurez besoin d'un pointeur isa sur votre classe de base si vous utilisez des variables d'instance. L'exécution s'attend à ce que ce soit là.

+0

Vous avez raison. Ça marche! Merci, c'est un grand pas pour moi :) – Eonil

2

Sur le moteur d'exécution d'Apple, les spécifications minimales sont assez facile à expliquer: Vous devez implémenter toutes les méthodes dans le protocole NSObject. Voir here. Ceci est absolument non-trivial. Vous voudrez peut-être ajouter quelques fonctions supplémentaires comme +alloc afin de pouvoir créer une instance, etc. Il n'y a que deux classes racines publiques dans tous les frameworks d'Apple: NSObject et NSProxy. En pratique, il n'y a absolument aucune raison de créer une classe racine. Je ne suis pas sûr qu'il existe une documentation sur ce problème par Apple. Ce que vous ferez en pratique est d'hériter de NSObject ou de NSProxy et de les construire par-dessus. Votre code ne fonctionnera que si vous effectuez les opérations suivantes:

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

Comme Tilo a souligné, ce n'est pas le cas sur d'autres runtimes comme le moteur d'exécution GNU.

+0

Vous avez raison Max:. la mise en œuvre d'une nouvelle classe de racine est difficile et peut être intéressant. d'un point de vue académique, mais dans la pratique il n'y a que très peu d'applications. – GorillaPatch

+0

en réalité, Apple a créé seulement 5 classes de racines dans tous les cadres de cacao, y compris NSObject et NSProxy. Je ne ai jamais eu la nécessité de créer un moi-même. –

+0

C'était juste une sorte d'essai faisant le programme d'objc sur la plate-forme non-Apple (comme FreeBSD). J'Agréée avec il n'y a aucune raison de faire ma propre classe racine dans la plate-forme d'Apple :) – Eonil

1

L'exemple ci-dessus se compile bien avec gcc et GNU-runtime. En Objective-C normalement n'importe quelle classe peut être une classe racine en n'ayant simplement pas de super classe. Si Apple-runtime nécessite quelque chose de différent, il est spécifique à l'exécution.

De plus il y a quelque chose de spécifique avec des classes de racines:

Toutes les méthodes d'instance sont également des méthodes de classe avec la même mise en œuvre (si pas mis en œuvre de façon explicite contraire). La sortie de l'application suivante:

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

serait:

class test 
instance test 
otherTest 
otherTest 

Le plus dur sur la création d'une nouvelle classe de racine est le +alloc et -dealloc, mais comme on le voit dans mon exemple le moteur d'exécution (dans mon cas le GNU-runtime) peut le faire. Mais je ne sais pas si l'allocation d'exécution est assez bonne. Je sais que certaines fondations utilisent un propre mécanisme d'allocation pour cacher le compteur de référence de la structure de l'objet. Je ne sais pas si Apple le fait aussi et si leur runtime s'en occupe déjà.

2

Dans mon système (GNUstep sur linux + GCC) J'ai dû remplacer la méthode alloc ci-dessus avec ce qui suit, pour faire le travail de l'échantillon. Je pense que cela est dû à une version plus récente obj-c exécution (documentation du moteur d'exécution ici:. Objective-C Runtime Reference de la Bibliothèque Mac Developer

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