Quelle est la meilleure pratique pour nommer les fichiers Swift qui ajoutent des extensions à des objets existants?

167

Il est possible d'ajouter des extensions aux types d'objets Swift existants à l'aide d'extensions, comme décrit dans la spécification du langage .

En conséquence, il est possible de créer des extensions telles que:

extension String {
    var utf8data:NSData {
        return self.dataUsingEncoding(NSUTF8StringEncoding, allowLossyConversion: false)!
    }
}

Cependant, quelle est la meilleure pratique de dénomination pour les fichiers source Swift contenant de telles extensions?

Dans le passé, la convention était d'utiliser extendedtype+categoryname.mpour le type Objective-C comme indiqué dans le guide Objective-C . Mais l'exemple Swift n'a pas de nom de catégorie et l'appeler String.swiftne semble pas approprié.

La question est donc: étant donné l' Stringextension ci-dessus , comment le fichier source swift doit-il être appelé?

AlBlue
la source
5
Ce n'est pas une question de révision de code - je me fiche de cet exemple particulier, je veux savoir quelle est la convention de nommage rapide.
AlBlue
2
Il n'y a pas de convention de dénomination. La seule chose sur laquelle nous devons continuer, ce sont les catégories d'Objective-C, qui ont toujours suivi le ClassName+ExtensionNameformat, et que je ne vois pas encore trop de gens utiliser. En outre, je trouve cela maladroit au lieu de simplement définir des classes et des extensions ensemble, ou de donner au fichier un meilleur nom comme FooAbleTypeset de définir des instances dans l'agrégat.
CodaFi
4
Il n'y a pas encore de pratique de dénomination. Voici une idée: regroupez toutes les extensions globales en une seule Extensions.swift. De cette façon, vous ne les perdrez pas de vue et les nouveaux arrivants dans la base de code les remarqueront immédiatement. Et je préfère garder les extensions ponctuelles privées pour le fichier dans lequel elles ont besoin.
Andrew
1
Comme le dit Andrew, il n'y a pas encore de pratique de dénomination standard - par conséquent, cette question a été posée spécifiquement pour obtenir des opinions afin qu'une communauté nouvellement formée puisse proposer des idées.
AlBlue
1
Un seul fichier extensions.swift est la voie à suivre à mon avis. Gardez la structure à l'intérieur organisée (à votre manière) pour trouver facilement ce dont vous avez besoin. Un seul fichier est facile à copier ou à lier à partir d'une variété de projets sans oublier de choses.
Yohst

Réponses:

202

La plupart des exemples que j'ai vus imitent l'approche Objective-C. L'exemple d'extension ci-dessus serait:

String+UTF8Data.swift

Les avantages sont que la convention de dénomination permet de comprendre facilement qu'il s'agit d'une extension et quelle classe est étendue.

Le problème avec l'utilisation Extensions.swiftou même StringExtensions.swiftest qu'il n'est pas possible de déduire le but du fichier par son nom sans regarder son contenu.

L'utilisation de l' xxxable.swiftapproche utilisée par Java fonctionne bien pour les protocoles ou les extensions qui ne définissent que des méthodes. Mais encore une fois, l'exemple ci-dessus définit un attribut donc cela UTF8Dataable.swiftn'a pas beaucoup de sens grammatical.

Picciano
la source
2
Bien que l'on puisse déduire ce qui est étendu par la convention de dénomination, c'est IHMO une complication inutile. Plutôt que des tonnes de fichiers <nom> + <extention> .swift, je garde un seul fichier extensions.swift que j'utilise généralement pour chaque projet. Le fichier est organisé en interne de manière à ce qu'il soit facile de trouver une classe particulière étendue.
Yohst
18
Cette réponse, <nom> + <extention> .swift, est en effet la façon dont Xcode le fait lors de la création de sous-classes NSManagedObject pour Core Data dans Xcode 8. Exemple: Foo + CoreDataProperties.swift.
Jerry Krinock
5
Et si l'extension implémentait plusieurs méthodes?
AlexVPerl
2
Soyez aussi descriptif que possible. Par exemple, si vous avez une extension à Image qui inclut une fonction différente pour appliquer des filtres, nommez-la Image + Filters.swift. Il est bien d'utiliser différents fichiers pour des groupes liés sur des fonctions étendues. Regroupez les choses liées ensemble, mais gardez les choses sans rapport séparées. La vie sera belle.
picciano
Si vous utilisez la convention de ExtendedType+Functionality.swift, est-il recommandé de trier toutes les Stringextensions, par exemple, dans leur propre sous-dossier (c'est String-à- dire ou String Extensions) sous le Extensionsdossier? Ou est-il préférable de simplement stocker tous les fichiers d'extension au même niveau sous le Extensionsdossier?
Noah Wilder le
9

Il n'y a pas de convention Swift. Rester simple:

StringExtensions.swift

Je crée un fichier pour chaque classe que j'étends. Si vous utilisez un seul fichier pour toutes les extensions, il deviendra rapidement une jungle.

Mike Taverne
la source
8
Cela ne semble pas particulièrement réutilisable.
Keller
1
Par rapport à?
Mike Taverne
3
Par rapport à un fichier unique (ou étroitement couplé) d'extensions de classe qui servent un objectif unique (ou expressément lié). Quelque chose comme "StringExtensions" semble pouvoir contenir tout, du nettoyage général des chaînes à la logique spécifique à l'application, ce qui pourrait ne pas être la meilleure approche si la réutilisation est un problème. La convention de dénomination Cocoa penche vers la fonction plutôt que vers la mise en œuvre. Je dirais que "StringExtensions" indique ce dernier. Hormis la convention de dénomination, je préfère la réponse acceptée, certainement dans ObjC, mais dans Swift, cela semble être une approche encore meilleure grâce aux modules.
Keller
2
Ça a du sens. Je pensais plus à une seule application où la réutilisation n'était pas un problème. Par exemple, disons que j'ai quelques fonctions de chaîne non liées que je souhaite utiliser comme extensions - je pourrais créer un fichier et y placer toutes ces fonctions, ou créer un fichier par fonction. J'aime la simplicité d'un seul fichier dans ce cas. Mais votre raisonnement est solide. Merci.
Mike Taverne
Cela a tout son sens, à condition que les éléments ajoutés ici s'appliquent naturellement à toutes les chaînes (par exemple, «trimRight ()»). Si c'est quelque chose qui est plus spécifique au cas d'utilisation (c'est-à-dire 'formatAccountNumber ()'), alors le fichier devrait être 'Strings + AccountFormatting.swift' et il devrait être limité uniquement là où il est réellement utilisé pour ne pas encombrer le API de surface 'Strings' ailleurs.
Mark A. Donohoe le
1

Je préfère StringExtensions.swiftjusqu'à ce que j'aie ajouté trop de choses pour diviser le fichier en quelque chose comme String+utf8Data.swiftet String+Encrypt.swift.

Une dernière chose, combiner des fichiers similaires en un seul rendra votre bâtiment plus rapide. Reportez - vous à Optimizing-Swift-Build-Times

DawnSong
la source
1
Cela a deux conventions de dénomination de fichier pour la même chose. Je pense que c'est mauvais.
sens-questions
@ le sens compte Cela dépend. Les deux conventions de dénomination sont à la fois bien connues et recommandées par Apple Documents. Tu fais comme tu veux.
DawnSong
Je souhaite que plus de programmeurs s'efforcent d'élégance en limitant les variations de noms et de codes [formatage].
sens-questions
@ sens-questions L'élégance a deux côtés, c'est comme un problème controversé classique sur la façon d'écrire des accolades dans des langages de type C. C'est trivial, donc je ne pense pas qu'il soit nécessaire d'en choisir un et de le rendre obligatoire jusqu'à ce que la plupart des gens acceptent de le faire.
DawnSong
Je voulais dire l'élégance de la cohérence: utiliser une façon de nommer les extensions, ou une façon de placer des accolades. Ensuite, je pense qu'il y a une différence mesurable dans la lisibilité des différents styles d'accolades; donc je ne pense pas du tout que ce soit «trivial».
sens-questions
0

Si vous avez un ensemble d'améliorations communes et diverses approuvées par l'équipe, les regrouper sous la forme d'une extension.swift fonctionne comme une solution de premier niveau Keep-It-Simple. Cependant, à mesure que votre complexité augmente ou que les extensions deviennent plus impliquées, une hiérarchie est nécessaire pour encapsuler la complexité. Dans de telles circonstances, je recommande la pratique suivante avec un exemple.

J'ai eu un cours qui parle à mon back-end, appelé Server. Il a commencé à s'agrandir pour couvrir deux applications cibles différentes. Certaines personnes aiment un gros fichier mais se séparent logiquement avec des extensions. Ma préférence est de garder chaque fichier relativement court, j'ai donc choisi la solution suivante. Serverà l'origine conforme CloudAdapterProtocolet implémenté toutes ses méthodes. Ce que j'ai fait, c'est transformer le protocole en hiérarchie, en le faisant référence à des protocoles subordonnés:

protocol CloudAdapterProtocol: ReggyCloudProtocol, ProReggyCloudProtocol {
    var server: CloudServer {
        get set
    }
    func getServerApiVersion(handler: @escaping (String?, Error?) -> Swift.Void)
}

Dans Server.swiftj'ai

import Foundation
import UIKit
import Alamofire
import AlamofireImage

class Server: CloudAdapterProtocol {
.
.
func getServerApiVersion(handler: @escaping (String?, Error?) -> Swift.Void) {
.
.
}

Server.swiftpuis implémente simplement l'API du serveur principal pour configurer le serveur et obtenir la version de l'API. Le vrai travail est divisé en deux fichiers:

Server_ReggyCloudProtocol.swift
Server_ProReggyCloudProtocol.swift

Ceux-ci mettent en œuvre les protocoles respectifs.

Cela signifie que vous devez avoir des déclarations d'importation dans les autres fichiers (pour Alamofire dans cet exemple), mais c'est une solution propre en termes de séparation des interfaces à mon avis.

Je pense que cette approche fonctionne aussi bien avec les classes spécifiées en externe que les vôtres.

Faisal Memon
la source
0

Pourquoi est-ce même un débat? Dois-je mettre toutes mes sous-classes dans un fichier appelé _Subclasses.swift. Je crois que non. Swift a un espacement des noms basé sur les modules. Pour étendre une classe Swift bien connue, il faut un fichier spécifique à son objectif. Je pourrais avoir une grande équipe qui crée un fichier qui est UIViewExtensions.swift qui n'exprime aucun but et qui confondra les développeurs et pourrait être facilement dupliqué dans le projet qui ne serait pas construit. La convention de dénomination Objective-C fonctionne bien et jusqu'à ce que Swift ait un espacement réel des noms, c'est la meilleure solution.

Tom Condon
la source
Dans mon cas, je pense qu'il est parfaitement logique d'avoir un fichier appelé UIViewExtensions.swift à condition que les extensions définies dans ce fichier aient un sens pour toutes les classes UIView, telles qu'une méthode 'placeIn (UIView)'. S'il est spécifique à l'utilisation (c'est-à-dire juste pour une partie de l'application, par exemple autour de la décoration de vue personnalisée, alors je ferais UIView + CustomDecoration.swift. Le fait est que vous devez considérer l'utilisation avant de faire une généralisation comme dire un fichier appelé 'UIViewExtensions .swift qui n'expriment aucun but 'lorsque le but est des extensions générales pour tous les UIViews.
Mark A. Donohoe
0

Plutôt que d'ajouter mes commentaires partout, je les expose tous ici en une seule réponse.

Personnellement, j'adopte une approche hybride qui donne à la fois une bonne convivialité et une bonne clarté, tout en n'encombrant pas la surface API de l'objet que j'étends.

Par exemple, tout ce qui a du sens pour être disponible pour n'importe quelle chaîne irait dans StringExtensions.swifttel que trimRight()et removeBlankLines().

Cependant, si j'avais une fonction d'extension telle formatAsAccountNumber()qu'elle n'entrerait pas dans ce fichier, car le `` numéro de compte '' n'est pas quelque chose qui s'appliquerait naturellement à toutes les chaînes et n'a de sens que dans le contexte des comptes. Dans ce cas, je créerais un fichier appelé Strings+AccountFormatting.swiftou peut-être même Strings+CustomFormatting.swiftavec une formatAsAccountNumber()fonction s'il existe plusieurs types / façons de le formater.

En fait, dans ce dernier exemple, je dissuade activement mon équipe d'utiliser des extensions comme celle-là en premier lieu, et j'encouragerais plutôt quelque chose comme à la AccountNumberFormatter.format(String)place car cela ne touche pas du tout la Stringsurface de l' API, comme cela ne devrait pas. L'exception serait si vous définissiez cette extension dans le même fichier où elle est utilisée, mais alors elle n'aurait pas son propre nom de fichier de toute façon.

Mark A. Donohoe
la source
0

Je préfère avoir un +pour souligner le fait qu'il contient des extensions:

String+Extensions.swift

Et si le fichier devient trop volumineux, vous pouvez le diviser pour chaque objectif:

String+UTF8Data.swift

String+Encrypt.swift

Xys
la source