Qual è la migliore pratica per nominare i file Swift che aggiungono estensioni agli oggetti esistenti?


165

È possibile aggiungere estensioni ai tipi di oggetti Swift esistenti usando le estensioni, come descritto nelle specifiche del linguaggio .

Di conseguenza, è possibile creare estensioni come:

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

Tuttavia, qual è la migliore pratica di denominazione per i file sorgente Swift contenenti tali estensioni?

In passato, la convenzione doveva essere utilizzata extendedtype+categoryname.mper il tipo Objective-C come discusso nella guida Objective-C . Ma l'esempio Swift non ha un nome di categoria e chiamarlo String.swiftnon sembra appropriato.

Quindi la domanda è: data l' Stringestensione sopra , come dovrebbe essere chiamato il file sorgente rapido?


4
Questa non è una domanda di codereview - non mi interessa questo esempio particolare, voglio sapere qual è la rapida convenzione di denominazione.
AlBlue,

2
Non esiste una convenzione di denominazione. L'unica cosa che dobbiamo seguire sono le categorie di Objective-C, che ha sempre seguito il ClassName+ExtensionNameformato e che non vedo ancora troppe persone che usano. Inoltre, trovo quel goffo al posto di definire insieme classi ed estensioni, o dare al file un nome migliore come FooAbleTypese definire istanze in aggregato.
CodaFi,

4
Non è ancora pratica di denominazione. Ecco un pensiero: raggruppa tutte le estensioni globali in una sola Extensions.swift. In questo modo, non perderai traccia di loro e i nuovi arrivati ​​nella base di codice li noteranno immediatamente. E preferirei mantenere le estensioni una tantum private per il file in cui sono necessarie.
Andrew,

1
Come dice Andrew, non esiste ancora una pratica di denominazione standard, quindi questa domanda è stata posta per ottenere opinioni specifiche in modo che una comunità appena formata possa venire ad alcune idee suggerite.
AlBlue,

1
Un singolo file extensions.swift è la strada da percorrere secondo me. Mantieni organizzata la struttura al suo interno (a modo tuo) per trovare facilmente ciò di cui hai bisogno. Un singolo file è facile da copiare o collegare da una varietà di progetti e non dimenticare cose.
Il

Risposte:


202

La maggior parte degli esempi che ho visto imitano l'approccio Objective-C. L'estensione di esempio sopra sarebbe:

String+UTF8Data.swift

I vantaggi sono che la convenzione di denominazione semplifica la comprensione del fatto che si tratta di un'estensione e di quale classe viene estesa.

Il problema con l'utilizzo Extensions.swifto addirittura StringExtensions.swiftè che non è possibile inferire lo scopo del file con il suo nome senza guardarne il contenuto.

L'uso xxxable.swiftdell'approccio usato da Java funziona bene per protocolli o estensioni che definiscono solo metodi. Ma ancora, l'esempio sopra definisce un attributo in modo che UTF8Dataable.swiftnon abbia molto senso grammaticale.


1
Sebbene si possa dedurre ciò che viene esteso dalla convenzione di denominazione, IHMO è una complicazione inutile. Piuttosto che tonnellate di <name> + <extention> .swift file, tengo un singolo file extensions.swift che generalmente uso per ogni progetto. Il file internamente è organizzato in modo tale che trovare una particolare classe estesa sia facile.
Il

18
Questa risposta, <name> + <extention> .swift, è in effetti il ​​modo in cui Xcode lo fa durante la creazione di sottoclassi NSManagedObject per i dati principali in Xcode 8. Esempio: Foo + CoreDataProperties.swift.
Jerry Krinock,

4
Cosa succede se l'estensione implementa più metodi?
AlexVPerl,

2
Sii il più descrittivo possibile. Ad esempio, se si dispone di un'estensione per Image che include funzioni diverse per l'applicazione di filtri, denominarla Image + Filters.swift. Va bene usare file diversi per gruppi correlati su funzioni estese. Raggruppa le cose correlate, ma tieni separate le cose non correlate. La vita sarà bella
picciano,

Se si utilizza la convenzione di ExtendedType+Functionality.swift, è buona norma ordinare tutte le Stringestensioni, ad esempio, nella propria sottocartella (ovvero Stringo String Extensions) nella Extensionscartella? O è meglio archiviare tutti i file delle estensioni sullo stesso livello nella Extensionscartella?
Noah Wilder,

8

Non esiste una convenzione Swift. Mantienilo semplice:

StringExtensions.swift

Creo un file per ogni classe che sto estendendo. Se usi un singolo file per tutte le estensioni, diventerà rapidamente una giungla.


8
Questo non sembra particolarmente riutilizzabile.
Keller,

1
Paragonato a?
Mike Taverne,

3
Rispetto a un file singolarmente (o strettamente accoppiato) di estensioni di classe che hanno un unico scopo (o espressamente correlabile). Qualcosa come "StringExtensions" suona come se potesse contenere qualsiasi cosa, dalla sanificazione delle stringhe per uso generale alla logica specifica dell'app, che potrebbe non essere l'approccio migliore se il riutilizzo è un problema. La convenzione sulla denominazione del cacao tende alla funzione, piuttosto che all'implementazione. Direi che "StringExtensions" indica quest'ultimo. A parte la convenzione di denominazione, preferisco la risposta accettata, certamente in ObjC, ma in Swift sembra un approccio ancora migliore grazie ai moduli.
Keller,

2
Questo ha senso. Stavo pensando più a una singola app in cui il riutilizzo non era un problema. Ad esempio, supponiamo che io abbia alcune funzioni di stringa non correlate che voglio usare come estensioni: potrei creare un file e inserire tutte queste funzioni o creare un file per funzione. Mi piace la semplicità di un singolo file in quel caso. Ma il tuo ragionamento è solido. Grazie.
Mike Taverne,

Ciò ha perfettamente senso, a condizione che le cose aggiunte qui si applichino naturalmente a tutte le stringhe (ad esempio "trimRight ()"). Se è qualcosa che è più specifico del caso d'uso (ad esempio 'formatAccountNumber ()'), il file dovrebbe essere 'Strings + AccountFormatting.swift' e dovrebbe essere impostato solo dove viene effettivamente utilizzato per non ingombrare il API di superficie "Stringhe" altrove.
Mark A. Donohoe,

1

Preferisco StringExtensions.swiftfino a quando non ho aggiunto troppe cose per dividere il file in qualcosa di simile String+utf8Data.swifte String+Encrypt.swift.

Un'altra cosa, combinare file simili in uno renderà il tuo edificio più veloce. Fare riferimento a Optimizing-Swift-Build-Times


1
Ci sono due convenzioni di denominazione dei file per la stessa cosa. Penso che sia male.
significato-argomenti

@ significato-importa Dipende. Le due convenzioni di denominazione sono entrambe ben note e consigliate da Apple Documents. Fai come vuoi.
DawnSong

Vorrei che più programmatori cercassero l'eleganza limitando le variazioni di denominazione e di codice [formattazione].
significato-argomenti

@ significato-materia L'eleganza ha due lati, è come un classico problema controverso su come scrivere parentesi graffe in linguaggi simili al C. È banale, quindi non credo sia necessario sceglierne uno e renderlo obbligatorio fino a quando la maggior parte delle persone non acconsente a farlo.
DawnSong

Intendevo l'eleganza della coerenza: usare un modo per nominare le estensioni o un modo per posizionare le parentesi graffe. Quindi penso che ci sia una differenza misurabile nella leggibilità dei diversi stili di parentesi graffe; quindi non penso che sia "banale".
significato-argomenti

0

Se disponi di una serie concordata di miglioramenti comuni e vari, raggruppandoli come Extensions.swift funziona come soluzione di primo livello Keep-It-Simple. Tuttavia, man mano che la complessità aumenta o le estensioni diventano più coinvolte, è necessaria una gerarchia per incapsulare la complessità. In tali circostanze raccomando la seguente pratica con un esempio.

Ho tenuto una lezione che parla al mio back-end, chiamata Server. Ha iniziato a crescere per coprire due diverse app target. Ad alcune persone piace un file di grandi dimensioni, ma logicamente diviso con estensioni. La mia preferenza è quella di mantenere ogni file relativamente breve, quindi ho scelto la seguente soluzione. Serveroriginariamente conforme CloudAdapterProtocole implementato tutti i suoi metodi. Quello che ho fatto è stato trasformare il protocollo in una gerarchia, facendo in modo che si riferisse a protocolli subordinati:

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

In Server.swiftho

import Foundation
import UIKit
import Alamofire
import AlamofireImage

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

Server.swiftquindi implementa semplicemente l'API del server principale per impostare il server e ottenere la versione dell'API. Il vero lavoro è diviso in due file:

Server_ReggyCloudProtocol.swift
Server_ProReggyCloudProtocol.swift

Questi implementano i rispettivi protocolli.

Significa che devi avere dichiarazioni di importazione negli altri file (per Alamofire in questo esempio) ma è una soluzione pulita in termini di separazione delle interfacce a mio avviso.

Penso che questo approccio funzioni ugualmente bene con le classi specificate esternamente e le tue.


0

Perché questo è persino un dibattito? Devo mettere tutte le mie sottoclassi in un file chiamato _Subclasses.swift. Penso di no. Swift ha una spaziatura dei nomi basata sul modulo. Per estendere una ben nota classe Swift è necessario un file specifico per il suo scopo. Potrei avere una grande squadra che crea un file che è UIViewExtensions.swift che non esprime alcuno scopo e confonde gli sviluppatori e potrebbe essere facilmente duplicato nel progetto che non sarebbe stato creato. La convenzione di denominazione Objective-C funziona bene e fino a quando Swift non ha una spaziatura dei nomi reale, è il modo migliore di procedere.


Nel mio caso, penso che abbia perfettamente senso avere un file chiamato UIViewExtensions.swift a condizione che le estensioni definite in quel file abbiano senso per qualsiasi / tutte le classi UIView, come un metodo 'placeIn (UIView)'. Se è specifico per l'uso (cioè solo per una parte dell'app, diciamo intorno alla decorazione della vista personalizzata, allora farei UIView + CustomDecoration.swift. Il punto è che devi considerare l'uso prima di fare una generalizzazione come dire un file chiamato 'UIViewExtensions .swift che non esprime alcuno "quando lo scopo è estensioni generali per tutte le UIVview.
Mark A. Donohoe

0

Piuttosto che aggiungere i miei commenti in tutto il luogo, li sto emergendo tutti qui in una risposta.

Personalmente, adotto un approccio ibrido che offre sia una buona usabilità che chiarezza, senza ingombrare la superficie dell'API per l'oggetto che sto estendendo.

Ad esempio, tutto ciò che ha senso essere disponibile per qualsiasi stringa andrebbe in StringExtensions.swiftcome trimRight()e removeBlankLines().

Tuttavia, se avessi una funzione di estensione come formatAsAccountNumber()questa non andrebbe in quel file perché "Numero account" non è qualcosa che si applicherebbe naturalmente a qualsiasi / tutte le stringhe e ha senso solo nel contesto degli account. In tal caso, creerei un file chiamato Strings+AccountFormatting.swifto forse anche Strings+CustomFormatting.swiftcon una formatAsAccountNumber()funzione se ci sono diversi tipi / modi per formattarlo effettivamente.

In realtà, in quell'ultimo esempio, ho dissuaso attivamente il mio team dall'utilizzare estensioni come quella in primo luogo, e incoraggerei invece qualcosa del genere AccountNumberFormatter.format(String)invece che non tocca affatto la Stringsuperficie dell'API, come non dovrebbe. L'eccezione sarebbe se tu avessi definito quell'estensione nello stesso file in cui è usata, ma non avrebbe comunque il suo nome file.


0

Preferisco avere un +per sottolineare il fatto che contiene estensioni:

String+Extensions.swift

E se il file diventa troppo grande, puoi quindi dividerlo per ogni scopo:

String+UTF8Data.swift

String+Encrypt.swift

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.