Equivalent de [self class]
JE729
Membre
Bonjour,
Je cherche seulement un moyen d'écrire [self class] en swift avant d avoir initialisé l'instance.
Imaginons le code ci dessous :
@interface MyObject : NSObject
- (instancetype)initWithName:(NSString *)name NS_DESIGNATED_INITIALIZER;
@property (readwrite, strong, nonatomic) NSString *name;
+ (NSString *)defaultName;
@end
@implementation MyObject
- (instancetype)initWithName:(NSString *)name
{
self = [super init];
if (self) {
_name = name;
}
return self;
}
- (instancetype)init
{
NSString *name = [[self class] defaultName]; // impossible à reproduire en swift
return [self initWithName:name];
}
+ (NSString *)defaultName
{
return @Untitled;
}
@end
Comment reproduire ca si c est possible ?
Connectez-vous ou Inscrivez-vous pour répondre.
Réponses
Voilà !
Il n'y a aucun moyen d'obtenir la classe d'un objet Switf pour faire un appel de méthode de classe dessus ?
Car là c'est gentil de passer par une ivar à la construction, mais ça ne résout pas le problème si on cherche à appeler des méthodes de factory ou autre.
Correction. On peut accéder les vars par nom mais, pour les méthodes, il faut utiliser self.dynamicType.maMethode() ou MyObject.maMethode()
Merci pour toutes ces réponses
J'arrive à ca :
J'arrive à ca
Les solutions fonctionnent mais non plus aucun intérêt car on ne peut pas sous classer et changer la valeur
Yoann a surement raison aucun moyen existe en pure swift
Il reste à essayer en passant par Objective-C et un bridging header mais c'est pas terrible terrible ...
N'utilises pas l'init pour initialiser le nom à défaut. Plutôt, utilises le class var et un lazy var comme ci :
OK, donc d'après ce que j'ai rapidement lu, la seule bonne méthode à appliquer c'est self.dynamicType.
Swift étant fait par des gens qui n'aiment pas le runtime dynamique, tu te retrouve avec tous les problèmes de sous classe de Java et autre : self.type renvois vers le type d'origine ayant défini une méthode et non une sous classe éventuelle. (ce qui est totalement débile de mon point de vue car c'est strictement identique à faire un appel explicite à la classe directement, aucun avantages)
Si tu veux faire comme en Objective-C et utiliser le runtime pour appeler une méthode de classe sur la classe effective à l'exécution (et donc autoriser les surcharge par les sous classes) tu dois passer par self.dynamicType.
@yoann JE729 a parfaitement résumé le problème :
Le truc c'est que si l'utilisation prohibée de self dans init() en Swift est totalement justifiée et une bonne idée à la base (cf les Use-Cases problématiques expliqués dans les confs WWDC à ce sujet), pour le cas de dynamicType c'est un peu particulier et je pense qu'ils pourraient l'autoriser. Ca vaudrait le coup de remonter un BugReport je pense pour signaler le cas d'usage et demander à ce que le compilateur fasse une exception pour ce type de cas de réflexion.
Après, dans tous les autres cas (en dehors d'une méthode d'init, une fois que l'objet est totalement initialisé et donc qu'il est autorisé d'utiliser self), aucun problème pour utiliser self.dynamicType en équivalent d'un [self class] qu'on utiliserait en ObjC. Ca marche très bien ailleurs. C'est juste dans le cas du init à cause de la restriction d'interdiction d'appeler self avant qu'il ait fini d'être totalement initialisé.
---
Je pense que pour ce genre de cas, la solution de Joanna (lazy initialized var) est la plus adaptée, et est même la solution qui est sans doute préconisée par les équipes de Swift dans ce cas (j'ai déjà vu des exemples Apple ressemblant à ce type de solution pour des problématiques similaires).
En gros, faire de la propriété "name" une lazy var avec defered initialization, ce qui permet du coup d'utiliser self.dynamicType après l'init grâce au côté lazy + defered init. Ce qui consiste tout simplement non pas à déclarer "var name: String?" d'un côté et affecter name à self.dynamicType.defaultName dans le init, mais déclarer + faire une initialisation lazy en même temps via "lazy var name: String? = { return self.dynamicType.defaultName }()".
Finalement c'est rien de + que ça la solution de Joanna, c'est ce que propose Swift pour solutionner ce problème d'init de variable qu'on ne peut faire qu'après / à l'extérieur du init.
Je vais surement diverger un peu du sujet mais pour le coup Swift me paraissait sexy et maintenant je le trouve plus que frustrant
Le problème de ce cas la avec le NSWindowController a été de nombreuses fois parlé sur StackOverflow et autres.
Il est pas hyper grave car la dernière solution fonctionne mais c'est frustrant...
Apres pour les nouveaux objets qu'on écrira, il y aura plus qu'à tricher comme fait plus haut avec le lazy
Je ne comprends pas bien pourquoi le premier cas est impossible ? Ca compile pas ?
Pour la 2ème solution, je ne vois pas en quoi l'utilisation du "lazy" est un hack. En fait je dirais plutôt que c'est la solution qu'on utilisait avant en ObjC qui est un hack parce qu'on n'avait pas mieux à l'époque... (et puis on s'y est tellement habitué qu'on a cru que c'était la norme)
Tu fais juste un "lazy var windowNibName: String? = { return self.className }()" dans ta classe parente, et c'est fini. Et si tu veux que ça soit une autre valeur dans une des sous-classes, tu overrides cette déclaration, ça devrait suffire je pense.
@JE729
Je ne me suis pas vraiment plongé dans Swift mais pour ton N°1 (class PrefWindowController : NSWindowController) si tu ne fournis pas de "designated initializer" et en fonction de ce que disent les règles d'héritages automatique tu ne peux pas tenter un qqchose comme ca ?
J'espère ne pas trop me mélanger les pinceaux avec ces histoires de designated et convenience
Ah ben oui, mais si tu veux appeler "self.init(windowNibName:)" depuis ton initializer, ça veut dire que cet initializer est un convenience init et pas un designated init.
Le "designated initializer" c'est l'initializer qui fait le gros du boulot et finit par appeler "super".
Un "convenience initializer" c'est un constructeur de commodité, qui finalement se contente d'appeler un autre constructeur, mais en déterminant en général lui-même la valeur de certains arguments.
Par exemple le designated initializer dans ton cas sera "init(windowNibName:)" puisque c'est lui qui fait tout le boulot et appelle super, et que de tout façon dans la classe mère cet initializer est déjà le designated init.
Mais par contre la méthode "init()" tout court, son rôle à elle c'est juste de te faciliter la vie et de se contenter au final d'appeler in fine "init(windowNibName:)" mais avec le bon argument automatiquement déterminé pour toi, plutôt que d'avoir à le rentrer à la main. Donc c'est de la commodité, au final, car il se contente de déterminer des valeurs par défaut et finir par appeler un autre initializer du même objet (self).
Si tu es perdu sur la différence entre les 2, il y a une session WWDC sur Swift qui explique cela plutôt bien, mais c'est aussi assez bien expliqué dans le PDF qu'a publié Apple concernant Swift sur le iBook Store.
Je viens tout juste de relire la section du bouquin ^^
Du coup, d'ou vient l'erreur quand je reste en convenience init(), j'avais joint un screenshot plus haut.(ca semble rien avoir)
Bonne question
De quelles sessions WWDC tu parles ? Je suis curieux de voir ce qu'ils ont à dire sur le sujet.
L'appel à self dans le init si le init est construit correctement n'est pas franchement un problème.
Il me semble aussi que c'est un peu abordé autour des pages 472 et suivantes du Swift Programming Language Book.
ça se trouve en session 403 entre 25:00 et 38:00
Je viens de regarder la session en question (merci Joanna pour la ref).
ça m'étonne de toi Ali mais tu as totalement extrapolé la documentation et les recommandations Apple pour arriver sur une assertion qui est fausse.
Tu dis "il est interdit d'utiliser "self" dans une méthode d'init", c'est totalement faux.
Ce qui est _déconseillé_, c'est d'appeler des getter et des setter qui vont envoyer les willChange et didChange du KVO et potentiellement foutre le bordel vu que l'objet n'est pas initialisé en plein.
Ce qui est également recommandé, c'est de n'appeler que des méthodes tierces qui sont explicitement prévu pour être appelé depuis le init (en clair : réfléchir 5 min à ce qu'on est en train d'écrire).
L'appel à self est tout sauf interdit et encore heureux ! Il est nécessaire dans bien des cas, y comrpis dans le designated initializer.
Les exemples montré dans la conférence Swift expliquant que "oh mon dieu, une méthode appelé dans le init peut être surchargé" sont juste complètement aberrant ! Heureusement qu'elles peuvent être surchargé ! Personnellement j'utilise ce genre de pratique à tout bout de champ pour économiser un maximum de code lorsque je travail sur des système à plugin (les truc qu'on a pas le droit d'utiliser sur iOS). La seule et unique bonne parade aux problèmes que cela peut poser est très simple : documenter son code.
Swift impose des gardes fou qui sont nécessaire pour forcer les fainéant à faire leur travail comme il faut. Mais il interdit aussi aux personnes compétentes de faire leur travail. C'est ce que je hais clairement dans ce langage.
Il a des fonctions très avancé, très intéressante, mais putain non, c'est hors de questions que je perde mon temps à écrire du code inutile pour un compilo paranoà¯aque.
Tout ce merdié est basé sur Clang Analyzer et cie. C'est très pratique en Objective-C de l'avoir à la demande et en recommandation uniquement. Et heureusement, car dès qu'on tombe sur des cas avancé (mix d'ObjC / C / C++, travail avec des structures, etc.) toutes ces guignoleries sont perdu.
Et pour ma part, tous les projets sur lesquels je bosse finissent toujours avec des truc du genre.
D'ailleurs, des apps aussi débile qu'ARD Inspector (un lecteur de base de donnée chiffré en AES) sont juste impossible à écrire en Swift. Le langage est tellement limité qu'il est impossible de se servir des décennies d'acquis en C. Si je veux me servir de CommonCrypto en Swift, je suis obliger d'en faire un wrapper Objective-C, quelle efficacité !
Je suis peut être un peu brute de décoffrage sur le sujet, mais le fait que tout le monde dise amen à un truc aussi mauvais et dangereux me fait peur.
Tout le monde dit "sa s'améliorera avec le temps" / "ils ne peuvent pas couper Objective-C, ils ont trop de code dessus" etc. mais quand on se rappel l'histoire de WebObject et des autres produits tué par Apple pour simple décision de manager alors que le produit se porte extrêmement bien, on ne peut qu'avoir peur.
Je te prie m'excuser si je ne t'ai pas bien entendu...
On ne parle pas de Objective-C, C++ ou même C, on parle de Swift, un tout nouveau langage. Ses concepteurs ont décidé d'introduire les nouveaux concepts qui ne sont pas comparables à ces autres langages, car ces concepts n'étaient pas auparavant réalisable.
Dès que l'arrivée de Swift, il n'est plus nécessaire de faire tous l'initialisation dans l'init, même l'init désigné. On a, désormais, les lazy vars, comme j'ai démontré au-dessus.
Les concepteurs ont également décidé d'introduire des "règles" qui sont là pour améliorer la fiabilité du code, non parce qu'ils veulent bouleverser le monde mais à cause des décennies d'experience des problèmes causé par les développeurs qui n'ont pas assez bien entendus ceux qu'ils fassent.
Peut-être tu es exceptionnel en n'ayant pas besoin d'aide à trouver les petits indiscrétions de logique mais, pendant les 23 dernières années comme développeur, j'ai appris que, le plus que le compilateur puisse me montrer comme source de soucis, le moins de temps je suis obligée de fouiller dans mon code et les docs pour trouver les soucis, souvent cachés, souvent bien obscurs.
Je me trouve parmi eux qui n'aime pas encore l'intégralité de Swift mais j'y trouver pas mal de bonnes idées et, bien que je viens d'avoir 60 ans, je suis contente de continuer à apprendre les nouveautés que ce langage nous apporte.
La vidéo que tu cite prend pour exemple l'Objective-C comme pratique dangereuse justifiant les limitations de Swift.
Quand aux lazy vars, désolé mais on peut le faire en ObjC, faut juste faire son travail de dev au lieu d'espérer que le compilo le fasse pour nous...
Si la communauté arrêtait de voir Swift comme un truc génial et prenait 5 min de pause pour mettre ça en perspective avec l'histoire d'Apple, je ne serais peut-être pas autant à cran sur le sujet.
On va dans un mur et tout le monde est content.
ça me sidère...
Que ce soit bien clair, les nouveautés technique de Swift, c'est gentil, ça servira peut être à certains, ça évitera aux SSII de faire de la merde, et ça donnera du boulot à tous les formateurs et conférencier pour 10 ans. Moi ça me va coté business.
Ce qui me fait extrêmement peur c'est la connerie qu'Apple est en train de faire vis à vis d'un marché mature et stable aujourd'hui.
Le système OS X et iOS ne survivra pas à un nouveau changement de langage. Les petits dev plierons le dos comme ils l'ont toujours fait, mais pas les grosses boites.
Avec autant de fanatisme autour de Swift que ce que l'on voit actuellement (formation sur un truc pas fini, conférence pour dire du vent autour d'un produit pas sorti, etc.), il y a toute les chance pour qu'Apple se lance dans un shift complet vers Swift pour les produits externe. Le résultat sera sans appel : appauvrissement de la plateforme.
Perso j'ai jamais dit que Swift était un truc trop génial et une révolution ni dit amen à tout ce qu'il y avait autour de Swift. Si tu le vois comme ça, c'est sans doute que tu as un filtre de perception négatif sur le sujet, à ne voir que le mauvais côté de la chose (pour être tout à fait franc, ça ne m'étonnerait pas de toi...)
J'apprécie pas mal de nouveautés de Swift car j'apprécie le renouvellement, les nouvelles idées, ça ouvre des horizons. Un peu comme un débat, je n'ai pas les idées arrêtées et j'apprécie les nouvelles propositions de réflexion autour de nouveaux concepts.
Je dis pas que toutes les idées sont bonnes ni que tout est parfait, loin de là .
Mais de là à dire à tout bout de champ que c'est de la grosse merde comme tu le fais, c'est un peu saoulant.
Et encore une fois le "faire de la merde" et cette idée tenace dans ton esprit que tout le monde fait de la merde si on ne fait pas selon ton idée. C'est saoulant comme discours.
Tu me sembles encore une fois très sectaire et surtout très carré sur ta vision des choses, tout blanc ou tout noir, et pas très ouvert à la discussion sur le sujet malheureusement. Ou plutôt ouvert à ... hijacker chaque discussion autour de Swift sur le forum pour à chaque fois ressortir le même terme comme quoi "c'est de la merde"...
Encore une vision noire et pessimiste qui t'es si propre... J'en viens presque à être désolé pour toi que tu ne vois que le côté négatif de choses... Je ne dis pas qu'il faut voir tout tout blanc, Swift est très loin d'être parfait. Mais il ouvre d'autres horizons, pas parfaits mais qui sont intéressants à considérer. Bref, c'est ni du tout blanc, ni du tout noir, mais de là à dire sans cesse que c'est de la merde, c'est saoulant.
Suite à ma solution originale...
Si on ne voulait pas hériter de NSObject, le code devrait être un peu différent