Quelle est la meilleure façon de résoudre un Objectif-C de l'espace de noms de collision?
Objective-C n'a pas d'espaces de noms; c'est un peu comme le C, le tout est dans un espace de noms global. La pratique courante est de préfixe des classes avec des initiales, par exemple, si vous travaillez au sein d'IBM, vous pouvez préfixer avec "IBM"; si vous travaillez pour Microsoft, vous pouvez utiliser "MS"; et ainsi de suite. Parfois les initiales reportez-vous à ce projet, par exemple Adium préfixes de classes avec "AI" (comme il n'y a pas d'entreprise derrière elle, ce que l'on pouvait prendre les initiales). Apple préfixes de classes avec NS et dit ce préfixe est réservé pour Apple uniquement.
C'est très bien. Mais en ajoutant 2 à 4 lettres pour un nom de classe à l'avant est un très, très peu d'espace de noms. E. g. MS ou IA pourrait avoir un tout autre sens (IA pourrait être l'Intelligence Artificielle par exemple) et quelques autres développeur peut décider de les utiliser et de créer un même nom de la classe. Bang, de l'espace de noms de collision.
Bon, si c'est une collision entre un de vos propres classes et un de un cadre externe que vous utilisez, vous pouvez facilement changer la dénomination de votre classe, pas une grosse affaire. Mais que faire si vous utilisez deux cadres, deux cadres que vous n'avez pas la source et que vous ne pouvez pas changer? Votre demande de liens avec les deux et vous obtenez des conflits de nom. Comment feriez-vous pour la résolution de ces? Quelle est la meilleure façon de travailler autour d'eux, de telle sorte que vous pouvez toujours utiliser les deux classes?
En C, vous pouvez contourner ces par ne pas relier directement à la bibliothèque, au lieu de charger la bibliothèque au moment de l'exécution, à l'aide de dlopen(), puis de trouver le symbole que vous recherchez à l'aide de dlsym() et de l'affecter à un symbole mondial (que vous pouvez nommer comme vous le souhaitez), puis accès par le biais de ce symbole mondial. E. g. si vous avez un conflit, parce que certains de la bibliothèque C a une fonction nommée open(), vous pouvez définir une variable nommée myOpen et de pointer à la fonction open() de la bibliothèque, ainsi, lorsque vous souhaitez utiliser le système open(), il suffit d'utiliser open() et lorsque vous souhaitez utiliser l'autre, vous y accédez via le myOpen identificateur.
Est quelque chose de semblable possible en Objective-C et si non, est-il un autre intelligent, rusé solution, vous pouvez utiliser de résoudre les conflits d'espace de noms? Des idées?
Mise à jour:
Juste pour clarifier ce: les réponses qui suggèrent comment éviter les collisions d'espace de noms à l'avance ou comment créer un meilleur espace de noms sont certainement les bienvenus; cependant, je ne vais pas l'accepter comme la réponse car ils ne permettent pas de résoudre mon problème. J'ai deux bibliothèques et leurs noms de classe entrent en collision. Je ne peux pas les changer, je n'ai pas la source de l'un des deux. La collision est déjà là et des conseils sur comment cela aurait pu être évité à l'avance ne sert plus à rien. Je peux transmettre les développeurs de ces cadres et de l'espoir qu'ils choisissent un meilleur espace de noms dans le futur, mais pour le moment, je suis à la recherche d'une solution de travail avec les cadres de la droite maintenant dans une seule application. Toutes les solutions pour rendre cela possible?
- Vous avez une bonne question (que faire si vous avez besoin de deux cadres qui ont une collision de nom), mais il est enterré dans le texte. Réviser pour le rendre plus clair, et vous éviter les réponses simplistes comme celui que vous avez maintenant.
- C'est mon plus gros reproche à la conception actuelle de l'Objective-C langue. Regardez les réponses ci-dessous; celles qui traitent de la question (NSBundle de déchargement, à l'aide de N', etc) sont hideux hacks qui ne doivent pas être nécessaire pour quelque chose d'aussi banal que d'éviter un conflit de noms.
- Amen. Je suis en train d'apprendre l'obj-c, et de frapper cette question. Est venu ici à la recherche d'une solution simple.... boiteux.
- Pour l'enregistrement, techniquement C et Objective-C de fournir un support pour de multiples espaces de nom — pas exactement ce que l'OP est à la recherche d', cependant. Voir objectivistc.tumblr.com/post/3340816080/...
- Hmm, je ne le savais pas. Une sorte de terrible décision de conception, non?
Vous devez vous connecter pour publier un commentaire.
Si vous n'avez pas besoin d'utiliser des classes de deux cadres, dans le même temps, et vous ciblez les plates-formes qui supportent NSBundle de déchargement (OS X 10.4 ou version ultérieure, pas de GNUStep de soutien), et le rendement n'est vraiment pas un problème pour vous, je crois que vous pouvez charger un cadre à chaque fois que vous devez utiliser une classe à partir d'elle, puis le décharger et charger l'autre quand vous avez besoin d'utiliser l'autre cadre.
Mon idée initiale était d'utiliser NSBundle de charger l'un des cadres, puis les copier ou renommer les classes à l'intérieur de ce cadre, et ensuite chargez l'autre cadre. Il y a deux problèmes avec cette. Tout d'abord, je ne pouvais pas trouver une fonction pour copier les données de relevé pour renommer ou copier une classe, et toutes les autres classes dans le premier cadre de référence de la renommé de la classe désormais référence à la classe de l'autre cadre.
Vous n'avez pas besoin de copier ou renommer une classe, si il y avait un moyen de copier les données pointées par un IMP. Vous pouvez créer une nouvelle classe et puis les copier sur ivars, les méthodes, les propriétés et les catégories. Beaucoup plus de travail, mais c'est possible. Cependant, vous avez toujours un problème avec les autres classes dans le cadre du référencement de la mauvaise classe.
EDIT: La différence fondamentale entre le C et Objective-C temps de fonctionnement est, comme je le comprends, quand les bibliothèques sont chargées, les fonctions dans les bibliothèques contiennent des pointeurs vers les symboles de référence, alors qu'en Objective-C, ils contiennent des représentations de chaîne de noms de thsoe symboles. Ainsi, dans votre exemple, vous pouvez utiliser dlsym d'obtenir le symbole de l'adresse dans la mémoire et de l'attacher à un autre symbole. L'autre code dans la bibliothèque fonctionne toujours parce que vous n'êtes pas changer l'adresse du symbole d'origine. Objective-C utilise une table de choix à la carte les noms de classe d'adresses, et c'est 1-1 de la cartographie, de sorte que vous ne pouvez pas avoir deux classes portant le même nom. Ainsi, pour charger les deux classes, l'une d'entre elles doivent avoir leur nom a changé. Toutefois, lorsque d'autres classes ont besoin pour accéder à l'une des classes de même nom, ils vont demander à la table de recherche pour son adresse, et la table de recherche ne sera jamais de retour l'adresse de la renommée classe de la classe d'origine de son nom.
De préfixer vos classes avec un préfixe unique est fondamentalement la seule option, mais il y a plusieurs façons de faire ce moins onéreuse et plus laid. Il y a une longue discussion des options ici. Mon préféré est le
@compatibility_alias
Objective-C directive du compilateur (décrit ici). Vous pouvez utiliser@compatibility_alias
"renommer" d'une classe, vous permettant de nom de votre classe à l'aide de nom de domaine complet ou un préfixe:Dans le cadre d'une stratégie complète, vous pouvez préfixer toutes vos classes avec un préfixe unique tels que le nom de domaine complet et ensuite créer un en-tête avec tous les
@compatibility_alias
(j'imagine que vous pourriez générer automatiquement le dit d'en-tête).La baisse de la préfixation comme cela, c'est que vous avez à entrer dans le véritable nom de la classe (par exemple,
COM_WHATEVER_ClassName
ci-dessus) dans tout ce qui doit être le nom de la classe à partir d'une chaîne en outre le compilateur. Notamment,@compatibility_alias
est une directive de compilation, et non pas à l'exécution de la fonction, de sorteNSClassFromString(ClassName)
sera un échec (retournil
)--vous devrez utiliserNSClassFromString(COM_WHATERVER_ClassName)
. Vous pouvez utiliseribtool
via phase de construction de modifier les noms de classe dans une Interface Builder nib/xib, de sorte que vous n'avez pas à écrire le plein COM_WHATEVER_... dans Interface Builder.D'avertissement Final: parce que c'est une directive de compilation (et un obscur à l'), il peut ne pas être portable sur l'ensemble des compilateurs. En particulier, je ne sais pas si cela fonctionne avec le Bruit frontend de la LLVM projet, même s'il devrait travailler avec LLVM-GCC (LLVM à l'aide de la GCC frontend).
Plusieurs personnes ont déjà partagé quelques délicate et intelligente de code qui pourrait aider à résoudre le problème. Certaines de ces suggestions peuvent travailler, mais ils sont tous de moins que l'idéal, et certains d'entre eux sont carrément méchant, à mettre en œuvre. (Parfois laid hacks sont inévitables, mais j'essaie de les éviter dès que je peux.) À partir d'un point de vue pratique, ici sont mes suggestions.
Je suppose que les frais de licence, les conditions et les durées peuvent empêcher l'action instantanée sur aucun de ces points. Nous espérons que vous serez en mesure de résoudre le conflit dès que possible. Bonne chance!
C'est brut, mais vous pouvez utiliser les objets distribués afin de garder l'une des classes que dans un subordonné programmes de l'adresse et de la RPC à elle. Qui va être gênant si vous êtes de passage à une tonne de trucs en arrière et en avant (et peut ne pas être possible si les deux de la classe sont manipulant directement les points de vue, etc).
Il y a d'autres solutions possibles, mais beaucoup d'entre eux dépendent de la situation exacte. En particulier, êtes-vous à l'aide de l'modernes ou plus anciens temps de fonctionnement, êtes-vous de la graisse ou de l'architecture unique, 32 ou 64 bits, quel système d'exploitation des rejets ciblez-vous, êtes-vous de manière dynamique de la liaison, la liaison statique, ou avez-vous un choix, et est-il potentiellement d'accord pour faire quelque chose qui peut nécessiter de l'entretien pour les nouvelles mises à jour du logiciel.
Si vous êtes vraiment désespéré, ce que vous pourriez faire est:
Ci-dessus est très intensive en main, et si vous avez besoin de la mettre en œuvre à l'encontre de plusieurs architectures et les différentes versions du moteur d'exécution, il sera très désagréable, mais il peut certainement être fait au travail.
Avez-vous envisagé d'utiliser le moteur d'exécution des fonctions (/usr/include/objc/runtime.h) pour cloner un conflit de classes pour les non-collision de la classe, puis le chargement de la collision cadre de la classe? (cela nécessiterait la collision des cadres chargés à différentes heures de travail.)
Vous pouvez inspecter les classes, ivars, les méthodes (avec les noms et la mise en œuvre des adresses) et les noms avec l'environnement d'exécution, et de créer votre propre ainsi dynamiquement pour avoir le même ivar mise en page, les méthodes de noms/mise en œuvre des adresses, et ne diffèrent que par le nom (pour éviter la collision)
Des situations désespérées appellent des mesures désespérées. Avez-vous envisagé de bidouiller le code de l'objet (ou le fichier de la bibliothèque) de l'une des bibliothèques, la modification de la collision symbole à un autre nom de la même longueur, mais une orthographe différente (mais, de recommandation, de la même longueur de nom)? Fondamentalement méchant.
Il n'est pas clair si votre code est directement en appelant les deux fonctions avec le même nom mais de différentes mises en œuvre ou, si le conflit est indirecte (il n'est pas clair si cela fait une différence). Cependant, il y a au moins une petite chance que le renommage serait de travailler. Il pourrait être une idée, aussi, de réduire la différence de l'orthographe, de sorte que, si les symboles sont dans un ordre de tri dans un tableau, le changement de nom ne fait pas avancer les choses dans le bon ordre. Des choses comme la recherche binaire se fâcher si le tableau qu'ils cherchent n'est pas dans l'ordre de tri comme prévu.
Il semble que le problème est que vous ne pouvez pas référencer les en-têtes de fichiers à partir de deux systèmes dans la même unité de traduction (fichier source). Si vous créez objective-c wrappers autour des bibliothèques (en les rendant plus utilisable dans le processus), et seulement #inclure les en-têtes de chaque bibliothèque dans la mise en œuvre des classes wrapper, qui permettrait de séparer efficacement les collisions de noms.
Je n'ai pas assez d'expérience avec ce en objective-c (juste de commencer), mais je crois que c'est ce que je ferais dans C.
@compatibility_alias
sera en mesure de résoudre classe conflits d'espace de noms, par exempleCependant, cela ne va pas résoudre tous les énumérations, typedefs, ou protocole de collisions d'espace de noms. En outre, il ne joue pas bien avec
@class
avant decls de la classe d'origine. Puisque la plupart des cadres qui viennent avec ces non-classe des choses comme les typedefs, vous ne serait probablement pas en mesure de résoudre le namespacing problème avec juste compatibility_alias.J'ai regardé un problème similaire au vôtre, mais j'ai eu accès à la source et de la construction de la cadres de.
La meilleure solution que j'ai trouvé pour ce a l'aide de
@compatibility_alias
conditionnellement avec #définit à l'appui de la enums/typedefs/protocoles/etc. Vous pouvez le faire de façon conditionnelle sur la compilation de l'unité pour l'en-tête en question afin de minimiser les risques d'expansion de choses dans l'autre collision cadre.Le préfixe des fichiers est la solution la plus simple j'en suis conscient.
Cocoadev a un espace de nom de la page qui est un effort de la communauté pour éviter les collisions de noms.
N'hésitez pas à ajouter votre propre à cette liste, je crois que c'est ce qu'il est pour.
http://www.cocoadev.com/index.pl?ChooseYourOwnPrefix
Si vous avez une collision, je vous suggère de réfléchir à la façon dont vous pourriez refactoriser un des cadres de votre application. Avoir une collision suggère que les deux font des choses semblables comme elle est, et il est probable que vous pourriez obtenir sur l'utilisation d'un supplément de cadre tout simplement par la refactorisation de votre application. Cela permettrait non seulement de résoudre votre problème de l'espace de noms, mais ce serait rendre votre code plus robuste, plus facile à maintenir et plus efficace.
Sur une solution technique, si j'étais dans votre position, ce serait mon choix.
Si la collision est seulement à la statique au niveau du lien, alors vous pouvez choisir de la bibliothèque est utilisée pour résoudre les symboles:
Si
foo.o
etbar.o
à la fois de référence, le symbolerat
puislibdog
résoudrefoo.o
'srat
etlibcat
résoudrebar.o
'srat
.Juste une pensée.. pas testé ou prouvé et peut être moyen de la marque, mais en avez-vous pensé à écrire un adaptateur pour la classe vous permet d'utiliser à partir de la plus simple des cadres.. ou au moins leurs interfaces?
Si vous deviez écrire un wrapper autour de la plus simple des cadres (ou de celui qui les interfaces vous accédez au moins) ne serait-il pas possible de compiler que wrapper dans une bibliothèque. Compte tenu de la bibliothèque est précompilé et seulement son les en-têtes doivent être distribué, Vous seriez en masquant le cadre sous-jacent et serait libre de le combiner avec le deuxième cadre avec des affrontements.
J'apprécie bien sûr qu'il y aura probablement des moments où vous avez besoin d'utiliser la classe à partir de deux cadres, dans le même temps, cependant, vous pouvez fournir les usines pour de plus amples classe des adaptateurs de ce cadre. Sur le dos de ce point, je crois que vous pourriez avoir besoin d'un peu de refactoring pour extraire les interfaces que vous utilisez à partir de deux cadres qui devrait fournir un bon point de départ pour vous de construire votre enveloppe.
Vous pouvez construire sur la bibliothèque comme vous et quand vous avez besoin de plus de fonctionnalités de la enveloppé de la bibliothèque, et simplement recompiler quand vous il change.
De nouveau, en aucune façon prouvée, mais se sentait comme l'ajout d'un point de vue. espérons que cela aide 🙂
Si vous avez deux cadres qui ont le même nom de fonction, vous pouvez essayer de les charger dynamiquement les cadres. Ça va être inélégant, mais possible. Comment le faire avec Objective-C classes, je ne sais pas. J'imagine que l'
NSBundle
classe de méthodes qui aurez la charge d'une classe spécifique.