¿Cuál es la mejor práctica para nombrar archivos Swift que agregan extensiones a objetos existentes?


165

Es posible agregar extensiones a los tipos de objetos Swift existentes usando extensiones, como se describe en la especificación del lenguaje .

Como resultado, es posible crear extensiones como:

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

Sin embargo, ¿cuál es la mejor práctica de nomenclatura para los archivos fuente de Swift que contienen tales extensiones?

En el pasado, la convención era usar extendedtype+categoryname.mpara el tipo Objective-C como se discutió en la guía Objective-C . Pero el ejemplo de Swift no tiene un nombre de categoría, y llamarlo String.swiftno parece apropiado.

Entonces la pregunta es: dada la Stringextensión anterior , ¿cómo debe llamarse el archivo fuente rápido?


44
Esta no es una pregunta de revisión de código: no me importa este ejemplo en particular, quiero saber cuál es la convención de nomenclatura rápida.
AlBlue

2
No existe una convención de nomenclatura. Lo único que tenemos que seguir son las categorías de Objective-C, que siempre siguieron el ClassName+ExtensionNameformato, y que no veo que mucha gente siga usando. Además, me parece torpe en lugar de solo definir clases y extensiones juntas, o darle al archivo un nombre mejor FooAbleTypesy definir instancias en conjunto.
CodaFi

44
Todavía no hay una práctica de nombres. He aquí un pensamiento: agrupe todas las extensiones globales en una sola Extensions.swift. De esa manera, no los perderá de vista y los recién llegados a la base de código los notarán de inmediato. Y preferiría mantener las extensiones únicas privadas para el archivo en el que se necesitan.
Andrew

1
Como dice Andrew, todavía no existe una práctica estándar de denominación; por lo tanto, se hizo esta pregunta para obtener opiniones específicamente para que una comunidad recién formada pueda llegar a algunas ideas sugeridas.
AlBlue

1
Un único archivo de extensiones.swift es el camino a seguir en mi opinión. Mantenga la estructura dentro de ella organizada (a su manera) para encontrar lo que necesita fácilmente. Es fácil copiar o vincular un solo archivo desde una variedad de proyectos y no olvidar cosas.
Yohst

Respuestas:


202

La mayoría de los ejemplos que he visto imitan el enfoque de Objective-C. La extensión de ejemplo anterior sería:

String+UTF8Data.swift

Las ventajas son que la convención de nomenclatura facilita la comprensión de que es una extensión y qué clase se está extendiendo.

El problema con el uso Extensions.swifto incluso StringExtensions.swiftes que no es posible inferir el propósito del archivo por su nombre sin mirar su contenido.

Usar el xxxable.swiftenfoque utilizado por Java funciona bien para protocolos o extensiones que solo definen métodos. Pero, de nuevo, el ejemplo anterior define un atributo para que UTF8Dataable.swiftno tenga mucho sentido gramatical.


1
Aunque se puede inferir lo que se extiende por la convención de nomenclatura, IHMO es una complicación innecesaria. En lugar de toneladas de archivos <nombre> + <extensión> .swift, mantengo un solo archivo de extensiones.swift que generalmente uso para cada proyecto. El archivo está organizado internamente de modo que sea fácil encontrar una clase particular que se extienda.
Yohst

18
Esta respuesta, <nombre> + <extensión> .swift, es de hecho la forma en que Xcode lo hace al crear subclases NSManagedObject para Core Data en Xcode 8. Ejemplo: Foo + CoreDataProperties.swift.
Jerry Krinock

44
¿Qué pasa si la extensión implementa múltiples métodos?
AlexVPerl

2
Solo sea lo más descriptivo posible. Por ejemplo, si tiene una extensión de imagen que incluye diferentes funciones para aplicar filtros, asígnele el nombre Image + Filters.swift. Está bien usar diferentes archivos para grupos relacionados en funciones extendidas. Agrupe cosas relacionadas, pero mantenga las cosas no relacionadas por separado. La vida sera buena.
picciano 01 de

Si está utilizando la convención de ExtendedType+Functionality.swift, ¿es una buena práctica clasificar todas las Stringextensiones, por ejemplo, en su propia subcarpeta (es decir, Stringo String Extensions) en la Extensionscarpeta? ¿O es mejor simplemente almacenar todos los archivos de extensión en el mismo nivel en la Extensionscarpeta?
Noah Wilder

8

No hay una convención rápida. Mantenlo simple:

StringExtensions.swift

Creo un archivo para cada clase que estoy ampliando. Si usa un solo archivo para todas las extensiones, rápidamente se convertirá en una jungla.


8
Esto no parece particularmente reutilizable.
Keller

1
¿En comparación con?
Mike Taverne

3
En comparación con un archivo individual (o estrechamente acoplado) de extensiones de clase que sirven para un único propósito (o expresamente relacionado). Algo parecido a "StringExtensions" parece que podría contener todo, desde la desinfección de cadenas de propósito general hasta la lógica específica de la aplicación, que podría no ser el mejor enfoque si la reutilización es una preocupación. La convención de nomenclatura de cacao se inclina hacia la función, en lugar de la implementación. Yo diría que "StringExtensions" indica lo último. Dejando de lado la convención de nombres, prefiero la respuesta aceptada, ciertamente en ObjC, pero en Swift parece un enfoque aún mejor debido a los módulos.
Keller

2
Eso tiene sentido. Estaba pensando más en una sola aplicación donde la reutilización no era una preocupación. Por ejemplo, supongamos que tengo algunas funciones de cadena no relacionadas que quiero usar como extensiones: podría crear un archivo y poner todas estas funciones allí, o crear un archivo por función. Me gusta la simplicidad de un solo archivo en ese caso. Pero tu razonamiento es sólido. Gracias.
Mike Taverne

Esto tiene mucho sentido, siempre que las cosas que se agregan aquí se apliquen naturalmente a todas las cadenas (es decir, 'trimRight ()' como ejemplo). Si es algo que es más específico para el caso de uso (es decir, 'formatAccountNumber ()'), entonces el archivo debe ser 'Strings + AccountFormatting.swift' y debe tener un alcance solo donde realmente se usa para no saturar el 'Strings' superficie API en otro lugar.
Mark A. Donohoe

1

Prefiero StringExtensions.swifthasta que agregué demasiadas cosas para dividir el archivo en algo como String+utf8Data.swifty String+Encrypt.swift.

Una cosa más, combinar archivos similares en uno hará que su edificio sea más rápido. Consulte Optimización-Swift-Build-Times


1
Eso es tener dos convenciones de nomenclatura de archivos para la misma cosa. Creo que eso es malo.
significado-asuntos

@ significado-importa Depende. Las dos convenciones de nomenclatura son conocidas y recomendadas por Apple Documents. Haz lo que desees.
DawnSong

Desearía que más programadores se esforzaran por la elegancia al limitar las variaciones de nombres y códigos [formateo].
significado-asuntos

@ significado-asuntos La elegancia tiene dos lados, es como un clásico problema controvertido sobre cómo escribir llaves en lenguajes tipo C. Es trivial, por lo que no creo que sea necesario elegir uno y hacerlo obligatorio hasta que la mayoría de la gente acepte hacerlo.
DawnSong

Me refería a la elegancia de la coherencia: usar una forma de nombrar extensiones o una forma de colocar llaves. Entonces sí creo que hay una diferencia apreciable en la legibilidad de los diferentes estilos de llaves; así que no creo que sea 'trivial' en absoluto.
significado-asuntos

0

Si tiene un conjunto de mejoras comunes y diversas acordadas por el equipo, agruparlas como Extensions.swift funciona como una solución de primer nivel Keep-It-Simple. Sin embargo, a medida que crece su complejidad, o las extensiones se involucran más, se necesita una jerarquía para encapsular la complejidad. En tales circunstancias, recomiendo la siguiente práctica con un ejemplo.

Tuve una clase que habla con mi back-end, llamada Server. Comenzó a crecer para cubrir dos aplicaciones de destino diferentes. A algunas personas les gusta un archivo grande pero simplemente se dividen lógicamente con extensiones. Mi preferencia es mantener cada archivo relativamente corto, así que elegí la siguiente solución. Serveroriginalmente conformado CloudAdapterProtocole implementado todos sus métodos. Lo que hice fue convertir el protocolo en una jerarquía, haciendo que se refiriera a protocolos subordinados:

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

En Server.swifttengo

import Foundation
import UIKit
import Alamofire
import AlamofireImage

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

Server.swiftluego solo implementa la API del servidor central para configurar el servidor y obtener la versión de la API. El verdadero trabajo se divide en dos archivos:

Server_ReggyCloudProtocol.swift
Server_ProReggyCloudProtocol.swift

Estos implementan los protocolos respectivos.

Significa que necesita tener declaraciones de importación en los otros archivos (para Alamofire en este ejemplo) pero es una solución limpia en términos de segregación de interfaces en mi opinión.

Creo que este enfoque funciona igualmente bien con clases especificadas externamente y con la suya propia.


0

¿Por qué es esto incluso un debate? ¿Debo poner todas mis subclases en un archivo llamado _Subclasses.swift? Yo creo que no. Swift tiene espaciado de nombre basado en módulo. Para extender una clase Swift bien conocida necesita un archivo que sea específico para su propósito. Podría tener un equipo grande que cree un archivo que sea UIViewExtensions.swift que no exprese ningún propósito y confunda a los desarrolladores y podría duplicarse fácilmente en el proyecto que no se construiría. La convención de nomenclatura Objective-C funciona bien y hasta que Swift tenga un espaciado de nombre real, es la mejor manera de hacerlo.


En mi caso, creo que tiene mucho sentido tener un archivo llamado UIViewExtensions.swift, siempre que las extensiones definidas en ese archivo tengan sentido para cualquiera / todas las clases de UIView, como un método 'placeIn (UIView)'. Si es específico del uso (es decir, solo para una parte de la aplicación, por ejemplo, alrededor de la decoración de la vista personalizada, entonces haría UIView + CustomDecoration.swift. El punto es que debe considerar el uso antes de hacer una generalización como decir un archivo llamado 'UIViewExtensions .swift que no expresa ningún propósito 'cuando el propósito es extensiones generales para todas las UIViews.
Mark A. Donohoe

0

En lugar de agregar mis comentarios por todas partes, los estoy exponiendo a todos aquí en una respuesta.

Personalmente, adopto un enfoque híbrido que brinda buena usabilidad y claridad, al mismo tiempo que no abarrota el área de superficie API para el objeto que estoy extendiendo.

Por ejemplo, cualquier cosa que tenga sentido para estar disponible para cualquier cadena iría StringExtensions.swiftcomo trimRight()y removeBlankLines().

Sin embargo, si tuviera una función de extensión, como formatAsAccountNumber()sería no ir en ese archivo porque 'Número de cuenta' no es algo que naturalmente aplicarse a cualquier / todas las cadenas y sólo tiene sentido en el contexto de las cuentas. En ese caso, crearía un archivo llamado Strings+AccountFormatting.swifto tal vez incluso Strings+CustomFormatting.swiftcon una formatAsAccountNumber()función si hay varios tipos / formas de formatearlo.

En realidad, en ese último ejemplo, disuadí activamente a mi equipo de usar extensiones como esa en primer lugar, y en su lugar alentaría algo como AccountNumberFormatter.format(String)eso, ya que eso no toca la Stringsuperficie de la API, como no debería. La excepción sería si definió esa extensión en el mismo archivo donde se usa, pero de todos modos no tendría su propio nombre de archivo.


0

Prefiero tener un +para subrayar el hecho de que contiene extensiones:

String+Extensions.swift

Y si el archivo se vuelve demasiado grande, puede dividirlo para cada propósito:

String+UTF8Data.swift

String+Encrypt.swift

Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.