Philosophie programmation et efficacité
Rocou
Membre
Bonjour,
J'ai une question triviale concernant la façon la plus propre de programmer en Objective_C/Cocoa.
Pour un développeur qui vient du monde C, faut-il remplacer les fonctions C par des classes où peut-on conserver la notion de fonctions?
Par exemple, dans mon application actuelle, j'initialise le contenu des objets de mon interface (NSPopupButton, NSTableView, etc.) dans la partie 'AwakeFromNib'. Il y a un bout de code par objet, ce qui, quand l'interface est chargée, devient lourdingue...
J'ai une question triviale concernant la façon la plus propre de programmer en Objective_C/Cocoa.
Pour un développeur qui vient du monde C, faut-il remplacer les fonctions C par des classes où peut-on conserver la notion de fonctions?
Par exemple, dans mon application actuelle, j'initialise le contenu des objets de mon interface (NSPopupButton, NSTableView, etc.) dans la partie 'AwakeFromNib'. Il y a un bout de code par objet, ce qui, quand l'interface est chargée, devient lourdingue...
Connectez-vous ou Inscrivez-vous pour répondre.
Réponses
Etant moi-même débutant en Cocoa, je ne saurais que trop te conseiller de lire ce livre avant de commencer à coder, cela évitera de prendre de mauvaises habitudes.
Voilà
En fait c'est à peu près le même principe pour les deux, mais une méthode est en quelques sortes une fonction que tu appelles sur un objet. C'est plus courant dans les langages orientés objet (par exemple tu demandes à ton objet "Voiture" de démarrer, plutôt que d'appeler une fonction demarrerLaVoiture(...))
Après bien sûr il est préférable de décomposer en effet. Pour reprendre ton exemple d'initialisation de ton interface, tu peux créer des méthodes dans le AppController où tu as mis ton awakeFromNib, par exemple une méthode "[tt]-(void)setContentsOfPopupButton:(NSPopupButton*)btn;[/tt]" que tu déclares dans ton AppController. Et du coup tout le code qui te sert à initialiser ton PopupButton, tu le déplaces de awakeFromNib vers cette méthode, et à la place dans awakeFromNib tu appelles la méthode via un [tt][self setContentsOfPopupButton:popupBtn];[/tt] (où popupBtn serait IBOutlet vers ton popupbutton bien sûr)
Voilà pour l'idée
C'est le cas typique de l'utilisation d'une fonction C au sein d'un code Obj-C par exemple.
Une petite fonction C pour regrouper le code d'initialisation d'un objet UI, et juste son appel dans le awakeFromNib est une solution viable, et effectivement, permet d'alléger le code en amont.
Bien sûr, comme dit Ali, la fonction peut être remplacée par une méthode spécifique et appelée via self.
mais bon, utiliser le mécanisme message/objet pour un bout de code privé est peut-être plus lourdingue que le simple emploi d'une bonne vieille fonction C.
Perso côté pédagogique je préfère orienter l'architecture de l'application en tout-objet, et donc habituder Rocou à la POO plutôt que de le faire trop se rattacher à ses principes du C où la notion d'objet est totalement absente... Ca permet donc en plus d'appréhender mieux la POO, et côté propreté je trouve ça plus clean... mais bon c'est un avis perso.
En effet rien ne t'empêche d'utiliser, en particulier dans ce cas, des fonctions C au lieu de méthodes Objective-C... ça fait moins POO mais ça marche aussi... mais bon perso moi je ne garde l'utilisation des fonctions C que pour les parties algorithmiques, genre calculs intensifs
Si c'est vraiment lié à la classe, on peut en faire une méthode de classe... sinon, si c'est plutôt générique (comme NSMakePoint par exemple), une fonction C est plus adéquate.
Sachant cela, il vous est possible de créer des "méthodes" privées pures, car, comme vous le savez/devriez le savoir aucune méthode n'est totalement privée en ObjC, il suffit de connaà®tre son nom pour pouvoir l'appeler, mais avec une fonction C, il vous est possible d'accéder aux ivars de votre objet tout en garantissant que cette fonction ne sera pas appelée par une personne malveillante :
Bien sûr, ici c'est pas un super exemple, un setter privé n'est pas le genre de trucs qu'on utilise souvent, mais ce genre de technique peut être utile dans d'autres cas, par exemple dans le cas d'une fonction qu'on utilise intensément, ou dans le cas de code qu'il ne faut pas dévoiler.
C'est presque comme le coup du hack des instances Obj-C sur la pile
Quitte à faire une fonction C, autant lui passer les in/out de manière classique et non l'objet en lui même...
Tout simplement parce que c'est anti-POO
Depuis quand une fonction C fait partie des méthodes de l'objet en Objective-C, quand bien même elle est dans le .m ?
Depuis que les méthodes ObjC sont des fonctions C avec des paramètres cachés, et le simple fait de les mettre dans le @implementation te permet de les faire fonctionner de la même manière. Et si tu veux tu peux même rajouter la méthode au runtime...
Ce que tu essaies de faire, c'est de by-passer les faiblesses du langage par des techniques extérieures à ce langage.
Ce qui s'appelle... un hack.
C'est que tu accèdes à des membres d'une classe dans une fonction qui n'est pas une méthode de cette classe... C'est ça qui est complètement anti-POO !
Si un jour le fonctionnement interne de l'Objective-C change pour mieux coller à l'encapsulation, ton code ne compilera plus... là est la limite de la définition du hack
Si, cette technique est un hack, alors les catégories le sont aussi...
Dans la définition de l'Objective-C, il n'est pas écrit qu'une fonction C dans le .m peut accéder aux propriétés privées de la classe. C'est par ailleurs quelque chose qui peut changer dans une future évolution du langage.
Imaginons un Objective-C 3.0 qui implémente les méthodes privées et interdise à la compilation ce que tu fais en renforçant l'encapsulation (pourrie actuellement) du langage... Ton code se retrouve alors caduque et tu vas devoir reprendre des centaines / milliers de lignes de code.
Alors qu'un code sans hacks de ce genre, il aura beau être écrit en Obj-C 1.0, il sera compilable avec le 2.0, le 3.0, le 4.0... car la compatibilité descendante est assurée à ce niveau.
Quant aux catégories, je ne vois pas le rapport, ça fait partie du langage ???
Justement non, les fonctions C ne sont pas des méthodes de la classe du point de vue du runtime, elles le sont du point de vue du compilateur.
Pour commencer, avant ObjC 2, tu pouvais accéder aux variables d'instance d'une classe à l'extérieur de celle-ci même si les ivars étaient @private ou @protected, tu avais cependant un avertissement de la part du compilateur te disant que cet accès pourrait ne plus marcher dans de futures implémentations...
Voilà qui est maintenant corrigé.
Cependant, cet avertissement n'a jamais existé et n'existe toujours pas quand tu utilises une ivar dans une fonction C à l'intérieur de @implementation, et c'est pas une violation d'encapsulation, non, c'est tout simplement parce que ObjC fonctionne comme cela, les méthodes sont simplement des fonctions static, c'est-à -dire emprisonnées dans leur unité de compilation, dont on récupère l'adresse et qu'on met dans une structure adaptée.
La différence entre la fonction C et la méthode c'est que la première ne sera pas enregistrée par le runtime, mais l'une comme l'autre ont accès aux ivars de self et des autres objets de la même classe.
Et je peux te garantir que ça ne changera pas avec d'autres version d'ObjC, car il s'agit des fondements, et d'ailleurs, si cela allait être changé, ils auraient mis des avertissements. :P
Montre moi une documentation officielle d'Objective-C, ou même un livre sur le langage disant que les fonctions C définies à l'intérieur de @implementation ont droit d'accéder aux i-var de la classe...
Si tu la trouves, je suis convaincu d'emblée (même si je ne l'utiliserai pas, trouvant ça quand même crado ) !
L'avertissement pour les accès extérieur, c'est parce que c'était tellement gros et tellement violent qu'ils se sont sentis obligés de le mettre ; ils n'avaient juste pas eu le temps de le fixer pour la 1.0 c'est tout :P
Il n'y a pas d'avertissements pour tout un tas de choses... à commencer par les méthodes non documentées.
Ils vont pas non plus tenir la main aux développeur pour tout... Chacun prend ses responsabilités :P
Personnellement, je ne prendrais pas ce risque et je ne le conseillerais à personne car ce n'est pas écrit dans la définition du langage, c'est tout...
De même que l'utilisation directe de "objc_msgSend" et tout un tas d'autres choses hein, c'est pas péjoratif ! :P
Bon, bien sûr ils ne conseillent pas au commun des mortels de l'utiliser directement, cependant ils montrent comment l'utiliser pour ceux qui veulent implémenter un bridge par exemple.
ocrtHowMessagingWorks
C'est nouveau ? Il me semblait avoir galéré pour trouver de la documentation dessus il y a quelques années ???
Et sinon je pourrais pas te dire si c'est si récent que ça, mais il est vrai que je n'ai découvert ça qu'assez récemment.
Y a pas mal d'explications, c'est bien foutu... Obj-C 2.0 nous a au moins apporté une doc correcte sur certains recoins obscurs du langage :P
D'une part parce que l'Objective-C est basé sur le C, mais son but est de rajouter une couche objet au langage C qui n'en n'a pas à la base. Si tu détournes le langage Objective-C pour faire du "C objet" à ta sauce (en utilisant éventuellement avec des moyens détournés les mêmes techniques que l'Objective-C utilise sous le capot, ce qui n'est pas dit), rien ne garantit la compatibilité en cas d'évolution. Certes c'est faisable... mais à quoi bon, surtout quand ça complique la lecture du programme et n'a aucune garantie de pérennité...
C'est comme si, en C, tu écrivais des trucs genre : Histoire d'accéder à la pile de façon détournée... (alors qu'en plus selon les compilateurs et si c'est du __stdcall ou autre, la pile ne sera pas ordonnée pareil...), ou comme si, je sais pas moi, dans un langage objet tu n'utilisais pas d'accesseurs pour tes variables alors que la POO le préconise, ...
Si on creuse bien, on peut tout faire... je dirais même on peut faire tout et n'importe quoi. En tiraillant le langage dans tous les sens, y'a toujours moyen de faire des trucs... mais à la base c'est pas prévu pour, c'est pas pensé pour.
Tu peux conduire ta voiture en marche arrière pendant tout un trajet si ça te chante, mais bon, c'est pas prévu pour quoi...