Swift es un lenguaje de programación compilado , multiparadigma y de propósito general de alto nivel creado por Chris Lattner en 2010 para Apple Inc. y mantenido por la comunidad de código abierto . Swift compila en código máquina y utiliza un compilador basado en LLVM . Swift se lanzó por primera vez en junio de 2014 [11] y la cadena de herramientas Swift se ha distribuido en Xcode desde la versión 6, lanzada en 2014.
Apple pretendía que Swift admitiera muchos conceptos básicos asociados con Objective-C , en particular el envío dinámico , la vinculación tardía generalizada , la programación extensible y características similares, pero de una manera "más segura", lo que facilita la detección de errores de software ; Swift tiene características que abordan algunos errores de programación comunes como la desreferenciación de punteros nulos y proporciona azúcar sintáctica para ayudar a evitar la pirámide de la perdición . Swift admite el concepto de extensibilidad de protocolo , un sistema de extensibilidad que se puede aplicar a tipos, estructuras y clases , que Apple promueve como un cambio real en los paradigmas de programación que denominan "programación orientada a protocolos" [12] (similar a los rasgos y las clases de tipos ). [13]
Swift fue presentado en la Conferencia Mundial de Desarrolladores (WWDC) de Apple de 2014. [14] Se actualizó a la versión 1.2 durante 2014 y se actualizó a Swift 2 en la WWDC de 2015. Inicialmente era un lenguaje propietario , pero la versión 2.2 se convirtió en software de código abierto bajo la Licencia Apache 2.0 el 3 de diciembre de 2015 para las plataformas de Apple y Linux . [15] [16]
A partir de la versión 3.0, la sintaxis de Swift experimentó una evolución significativa, y el equipo central hizo de la estabilidad de la fuente un foco en las versiones posteriores. [17] [18] En el primer trimestre de 2018, Swift superó a Objective-C en popularidad medida. [19]
Swift 4.0, lanzado en 2017, introdujo varios cambios en algunas clases y estructuras integradas. El código escrito con versiones anteriores de Swift se puede actualizar utilizando la funcionalidad de migración integrada en Xcode. Swift 5, lanzado en marzo de 2019, introdujo una interfaz binaria estable en las plataformas de Apple, lo que permite que el entorno de ejecución de Swift se incorpore a los sistemas operativos de Apple. Es compatible con Swift 4 en cuanto a código fuente. [20]
Swift 5.1 se lanzó oficialmente en septiembre de 2019. Swift 5.1 se basa en la versión anterior de Swift 5 al extender las características estables del lenguaje al tiempo de compilación con la introducción de la estabilidad del módulo. La introducción de la estabilidad del módulo permite crear y compartir marcos binarios que funcionarán con futuras versiones de Swift. [21]
Swift 5.5, anunciado oficialmente por Apple en la WWDC de 2021 , amplía significativamente el soporte del lenguaje para la concurrencia y el código asincrónico , introduciendo notablemente una versión única del modelo de actor . [22]
Swift 5.9 se lanzó en septiembre de 2023 e incluye un sistema de macros, paquetes de parámetros genéricos y funciones de propiedad como el nuevo consume
operador. [23]
Swift 5.10 se lanzó en marzo de 2024. Esta versión mejora el modelo de concurrencia del lenguaje, lo que permite un aislamiento total de los datos para evitar las carreras de datos . También es la última versión antes de Swift 6. [24] La versión 5.10 está actualmente disponible para macOS, Windows y Linux. [25]
Swift 6 se lanzó en septiembre de 2024. [26]
El desarrollo de Swift comenzó en julio de 2010 por Chris Lattner , con la colaboración eventual de muchos otros programadores de Apple . Swift fue motivado por la necesidad de un reemplazo para el lenguaje de programación anterior de Apple, Objective-C , que había permanecido prácticamente sin cambios desde principios de la década de 1980 y carecía de características de lenguaje modernas. Swift tomó ideas de lenguaje "de Objective-C , Rust , Haskell , Ruby , Python , C# , CLU y muchos otros para enumerarlos". [7] El 2 de junio de 2014, la aplicación de la Conferencia Mundial de Desarrolladores de Apple (WWDC) se convirtió en la primera aplicación lanzada públicamente escrita con Swift. [27] Se lanzó una versión beta del lenguaje de programación para los desarrolladores de Apple registrados en la conferencia, pero la compañía no prometió que la versión final de Swift sería compatible con el código fuente de la versión de prueba. Apple planeó hacer que los convertidores de código fuente estuvieran disponibles si fuera necesario para el lanzamiento completo. [27]
El lenguaje de programación Swift , un manual gratuito de 500 páginas, también se lanzó en la WWDC y está disponible en Apple Books Store y en el sitio web oficial. [28]
Swift alcanzó el hito 1.0 el 9 de septiembre de 2014, con el Gold Master de Xcode 6.0 para iOS . [29] Swift 1.1 se lanzó el 22 de octubre de 2014, junto con el lanzamiento de Xcode 6.1. [30] Swift 1.2 se lanzó el 8 de abril de 2015, junto con Xcode 6.3. [31] Swift 2.0 se anunció en la WWDC 2015 y se puso a disposición para publicar aplicaciones en la App Store el 21 de septiembre de 2015. [32] Swift 3.0 se lanzó el 13 de septiembre de 2016. [33] Swift 4.0 se lanzó el 19 de septiembre de 2017. [34] Swift 4.1 se lanzó el 29 de marzo de 2018. [35]
Swift ganó el primer lugar como lenguaje de programación más querido en la encuesta de desarrolladores de Stack Overflow 2015 [36] y el segundo lugar en 2016. [37]
El 3 de diciembre de 2015, el lenguaje Swift, las bibliotecas de soporte, el depurador y el administrador de paquetes se convirtieron en código abierto bajo la licencia Apache 2.0 con una excepción de biblioteca de tiempo de ejecución [38] y se creó Swift.org para alojar el proyecto. El código fuente está alojado en GitHub, donde es fácil para cualquiera obtener el código, compilarlo por sí mismo e incluso crear solicitudes de incorporación de código para contribuir al proyecto.
En diciembre de 2015, IBM anunció su sitio web Swift Sandbox, que permite a los desarrolladores escribir código Swift en un panel y mostrar el resultado en otro. [39] [40] [41] Swift Sandbox quedó obsoleto en enero de 2018. [42]
Durante la WWDC 2016 , Apple anunció una aplicación exclusiva para iPad , llamada Swift Playgrounds , destinada a enseñar a las personas a codificar en Swift. La aplicación se presenta en una interfaz similar a la de un videojuego en 3D que brinda información cuando las líneas de código se colocan en un orden determinado y se ejecutan. [43] [44] [45]
En enero de 2017, Chris Lattner anunció su salida de Apple para ocupar un nuevo puesto en Tesla Motors , y el papel de líder del proyecto Swift pasó a manos del veterano del equipo Ted Kremenek. [46] [47]
Durante la WWDC 2019, Apple anunció SwiftUI con Xcode 11, que proporciona un marco para el diseño de estructuras de interfaz de usuario declarativas en todas las plataformas de Apple. [48]
Las descargas oficiales del SDK y la cadena de herramientas para la distribución Ubuntu de Linux están disponibles desde Swift 2.2, y se han añadido más distribuciones desde Swift 5.2.4, CentOS y Amazon Linux. [49] También hay un paquete de SDK y cadena de herramientas nativo no oficial para Android. [50] [51]
Las plataformas compatibles con Swift son los sistemas operativos de Apple ( Darwin , iOS , iPadOS , macOS , tvOS , watchOS ), Linux , Windows y Android . [52] [53]
Un aspecto clave del diseño de Swift es su capacidad de interoperar con el enorme volumen de código Objective-C existente desarrollado para productos de Apple durante las décadas anteriores, como los frameworks Cocoa y Cocoa Touch . En las plataformas de Apple, [54] se vincula con la biblioteca de tiempo de ejecución Objective-C , que permite que el código C , Objective-C , C++ y Swift se ejecuten dentro de un programa. [55]
Swift es un lenguaje de programación de propósito general que emplea conceptos teóricos de lenguajes de programación modernos y busca presentar una sintaxis simple pero poderosa. Swift incorpora innovaciones y convenciones de varios lenguajes de programación, con una notable inspiración de Objective-C, al que reemplazó como el lenguaje de desarrollo principal en las plataformas de Apple.
Swift fue diseñado para ser seguro y amigable para los nuevos programadores sin sacrificar la velocidad. De manera predeterminada, Swift administra toda la memoria automáticamente y garantiza que las variables siempre se inicialicen antes de su uso. Los accesos a matrices se verifican para detectar errores fuera de límites y las operaciones con números enteros se verifican para detectar desbordamientos. Los nombres de parámetros permiten crear API claras. Los protocolos definen interfaces que los tipos pueden adoptar, mientras que las extensiones permiten a los desarrolladores agregar más funciones a los tipos existentes. Swift permite la programación orientada a objetos con soporte para clases , subtipos y anulación de métodos . Los opcionales permiten que los valores nulos se manejen de manera explícita y segura. Los programas concurrentes se pueden escribir utilizando la sintaxis async/await y los actores aíslan el estado mutable compartido para eliminar las carreras de datos. [72] [73]
La sintaxis de Swift es similar a la de los lenguajes de estilo C. El código comienza a ejecutarse en el ámbito global de forma predeterminada. [74] Alternativamente, se puede aplicar al atributo una declaración de estructura, clase o enumeración para indicar que contiene el punto de entrada del programa. [75]@main
El programa "¡Hola, mundo!" de Swift es:
imprimir ( "¡Hola, mundo!" )
La función que se utiliza aquí está incluida en la biblioteca estándar de Swift, que está disponible para todos los programas sin necesidad de importar módulos externos. Las sentencias en Swift no tienen que terminar con un punto y coma, sin embargo, se requieren puntos y comas para separar varias sentencias escritas en la misma línea. Los comentarios de una sola línea comienzan con y continúan hasta el final de la línea actual. Los comentarios de varias líneas están contenidos por los caracteres y . Las constantes se declaran con la palabra clave y las variables con la palabra clave . Los valores deben inicializarse antes de leerse. Los valores pueden inferir su tipo en función del tipo del valor inicial proporcionado. Si el valor inicial se establece después de la declaración del valor, se debe declarar un tipo explícitamente. [74]print(_:separator:terminator:)
//
/*
*/
let
var
deje que highScoreThreshold = 1000 // Una constante con tipo Int. El tipo se infirió en función del valor proporcionado.var currentScore = 980 // Una variable con tipo Int.currentScore = 1200 // El valor de las variables puede cambiar con el tiempo.deje que playerMessage : String // Una constante con tipo explícito String.si currentScore > highScoreThreshold { playerMessage = "¡Eres un jugador top!"} demás { playerMessage = "Mejor suerte la próxima vez."}print ( playerMessage ) // Imprime "¡Eres un jugador top!"
El flujo de control en Swift se gestiona con sentencias if-else , guard y switch , junto con bucles while y for-in . Las sentencias toman un parámetro booleano y ejecutan el cuerpo de la sentencia si la condición es verdadera; de lo contrario, ejecuta el cuerpo opcional. La sintaxis proporciona una sintaxis sencilla para comprobar la existencia de un valor opcional y desenvolverlo al mismo tiempo.if
if
else
if-let
sea algúnNúmero = 42si someNumber % 2 == 0 { // Utilice el operador de resto para encontrar el resto de someNumber dividido por 2. print ( " \( someNumber ) es par." )} demás { print ( " \( someNumber ) es impar." )}// Imprime "42 es par".
Las funciones se definen con la
palabra clave. Los parámetros de función pueden tener nombres que permiten que las llamadas a funciones se lean como frases. Un guión bajo antes del nombre del parámetro permite que la etiqueta del argumento se omita en el sitio de la llamada. Las funciones pueden usar tuplas para devolver varios datos a la vez.func
func constructGreeting ( para nombre : String ) -> String { devuelve "Hola \( nombre ) !"}deje que saludo = construyaSaludo ( para : "Craig" )imprimir ( saludo ) // Imprime "¡Hola Craig!"
Las funciones, y las funciones anónimas conocidas como cierres , pueden asignarse a propiedades y pasarse por el programa como cualquier otro valor.
func dividePorDos ( _aNum : Int ) - > Int { devuelve aNum / 2}func multiplicarPorDos ( _ aNum : Int ) -> Int { devuelve aNum * 2}deje que mathOperation = multiplicarPorDosprint ( mathOperation ( 21 )) // Imprime "42"
Las declaraciones requieren que la condición dada sea verdadera antes de continuar más allá de la declaración, de lo contrario se ejecuta guard
el cuerpo de la cláusula proporcionada . La cláusula debe salir del control del bloque de código en el que aparece la declaración. Las declaraciones son útiles para garantizar que se cumplan ciertos requisitos antes de continuar con la ejecución del programa. En particular, se pueden utilizar para crear una versión sin envolver de un valor opcional que se garantiza que no sea nulo durante el resto del ámbito que lo encierra.guard
else
else
guard
guard
func divide ( numerador : Int ?, porDenominador denominador : Int ) -> Int ? { denominador de guardia != 0 de lo contrario { imprimir ( "No se puede dividir por 0." ) devolver cero } guardia deja numerador else { imprimir ( "El numerador proporcionado es nulo." ) devolver cero } devolver numerador / denominador}sea resultado = dividir ( numerador : 3 , pordenominador : 0 )print ( "El resultado de la división es: \( resultado ) " )// Impresiones:// "No se puede dividir por 0."// "El resultado de la división es: nulo."
switch
Las declaraciones comparan un valor con múltiples valores potenciales y luego ejecutan un bloque de código asociado. switch
Las declaraciones deben ser exhaustivas, ya sea incluyendo casos para todos los valores posibles o incluyendo un default
caso que se ejecuta cuando el valor proporcionado no coincide con ninguno de los otros casos. switch
Los casos no se descartan implícitamente, aunque pueden hacerlo explícitamente con la fallthrough
palabra clave. La coincidencia de patrones se puede utilizar de varias maneras dentro de switch
las declaraciones. Aquí hay un ejemplo de un entero que se compara con una serie de rangos potenciales:
sea algúnNúmero = 42cambiar algúnNumero {caso ..< 0 : imprimir ( " \( someNumber ) negativo." )caso 0 : imprimir ( " \( someNumber ) es 0." )caso 1. .. 9 : print ( " \( someNumber ) mayor que 0, pero menor que 10." )por defecto : print ( " \( someNumber ) es mayor que 9." )}// Imprime "42 es mayor que 9."
for-in
Los bucles iteran sobre una secuencia de valores:
deje que los nombres sean = [ "Will" , "Anna" , "Bart" ]para nombre en nombres { imprimir ( nombre )}// Impresiones:// Voluntad// Ana//Bart
while
Los bucles se repiten mientras la condición booleana dada se evalúe como true
:
//Suma todos los números del 1 al 5.var i = 1var resultado = 0mientras i <= 5 { // El bucle ejecuta su cuerpo siempre que i sea menor o igual a 5. resultado += i // Agrega i al resultado actual. i += 1 // Incrementa i en 1.}imprimir ( resultado ) // Imprime "15"
Swift admite cierres , que son bloques de funcionalidad autónomos que se pueden pasar y usar en el código, [76] y también se pueden usar como funciones anónimas . A continuación, se muestran algunos ejemplos:
// El tipo de cierre, definido por sus valores de entrada y salida, se puede especificar fuera del cierre:deje que el cierre1 : ( Int , Int ) -> Int = { arg1 , arg2 en devuelve arg1 + arg2}//…o dentro de ella:deje que el cierre2 = { ( arg1 : Int , arg2 : Int ) -> Int en devuelve arg1 + arg2}// En la mayoría de los casos, el compilador puede inferir automáticamente el tipo de retorno del cierre.deje que el cierre3 = { arg1 : Int , arg2 : Int en devuelve arg1 + arg2}
Los cierres se pueden asignar a variables y constantes, y se pueden pasar a otras funciones o cierres como parámetros. Los cierres de expresión única pueden omitir la return
palabra clave.
Swift también tiene una sintaxis de cierre final, que permite escribir el cierre después del final de la llamada a la función en lugar de dentro de la lista de parámetros de la función. Los paréntesis se pueden omitir por completo si el cierre es el único parámetro de la función:
// Esta función toma un cierre que no recibe parámetros de entrada y devuelve un entero,// lo evalúa y utiliza el valor de retorno del cierre (un Int) como el valor de retorno de la función.func foo ( cierre bar : () -> Int ) -> Int { barra de retorno ()}// Sintaxis sin cierre final:foo ( cierre : { return 1 })// Con sintaxis de cierre final y retorno implícito:foo { 1 }
A partir de la versión 5.3, Swift admite múltiples cierres finales: [77]
// Esta función pasa el retorno del primer cierre como parámetro del segundo, // y devuelve el resultado del segundo cierre: func foo ( bar : () -> Int , baz : ( Int ) -> Int ) -> Int { return baz ( bar ()) }// Sin cierres finales: foo ( bar : { return 1 }, baz : { x in return x + 1 })// Con 1 cierre final: foo ( bar : { return 1 }) { x en return x + 1 }// Con 2 cierres finales (solo se omite el nombre del argumento del primer cierre): foo { return 1 } baz : { x in return x + 1 }
Swift proporcionará nombres de argumentos abreviados para los cierres en línea, eliminando la necesidad de nombrar explícitamente todos los parámetros de los cierres. [78] Se puede hacer referencia a los argumentos con los nombres $0, $1, $2, etc.:
deje que los nombres = [ "Josephine" , "Steve" , "Chris" , "Barbara" ]// filter llama al cierre dado para cada valor en names. // Los valores con un conteo de caracteres menor a 6 se conservan, los demás se descartan. let shortNames = names . filter { $0 . count < 6 }print ( shortNames ) // Imprime "["Steve", "Chris"]"
Los cierres pueden capturar valores de su ámbito circundante. El cierre hará referencia a este valor capturado mientras exista:
func makeMultiplier ( withMultiple multiple : Int ) -> ( Int ) -> ( Int ) { // Crea y devuelve un cierre que toma un Int y devuelve la entrada multiplicada por el valor de multiple. return { $0 * multiple } }deje que multiplicador = hacerMultiplicador ( conMultiple : 3 ) imprima ( multiplicador ( 3 )) // Imprime "9" imprima ( multiplicador ( 10 )) // Imprime "30"
String
La biblioteca estándar de Swift incluye tipos y que cumplen con Unicode Character
. Los valores de cadena se pueden inicializar con un literal de cadena, una secuencia de caracteres entre comillas dobles. Las cadenas se pueden concatenar con el +
operador:
var someString = "Hola", someString += "mundo!"
La interpolación de cadenas permite la creación de una nueva cadena a partir de otros valores y expresiones. Los valores escritos entre paréntesis precedidos por un \
se insertarán en la cadena literal que los contiene: [79]
var currentScore = 980 print ( "Su puntuación es \( currentScore ) ." )// Imprime "Tu puntuación es 980."
Se puede utilizar un bucle for-in para iterar sobre los caracteres contenidos en una cadena:
para el personaje en "Swift" { print ( character ) } // S // w // i // f // t
Cuando se importa el marco Foundation, Swift conecta de forma invisible el tipo String con NSString, la clase String comúnmente utilizada en Objective-C.
En Swift, los objetos invocables se definen utilizando callAsFunction
. [80]
struct CallableStruct { var valor : Int func callAsFunction ( _ numero : Int , escala : Int ) { print ( escala * ( numero + valor )) } } let callable = CallableStruct ( valor : 100 ) callable ( 4 , escala : 2 ) callable.callAsFunction ( 4 , escala : 2 ) // Ambas llamadas de función imprimen 208.
Swift admite cinco niveles de control de acceso para símbolos: open
, public
, , y . A diferencia de muchos lenguajes orientados a objetos, estos controles de acceso ignoran las jerarquías de herencia : indica que un símbolo es accesible solo en el ámbito inmediato , indica que es accesible solo desde dentro del archivo, indica que es accesible dentro del módulo que lo contiene, indica que es accesible desde cualquier módulo y (solo para clases y sus métodos) indica que la clase puede ser subclasificada fuera del módulo. [81]internal
fileprivate
private
private
fileprivate
internal
public
open
Una característica importante de Swift son los tipos opcionales , que permiten que las referencias o los valores funcionen de manera similar al patrón común en C , donde un puntero puede hacer referencia a un valor específico o a ningún valor en absoluto. Esto implica que los tipos no opcionales no pueden generar un error de puntero nulo ; el compilador puede garantizar que esto no sea posible.
Los tipos opcionales se crean con la Optional
enumeración. Para crear un entero que admita valores nulos, se usaría una declaración similar a var optionalInteger: Optional<Int>
. Como en C#, [82] Swift también incluye sintaxis para esto, lo que permite indicar que una variable es opcional colocando un signo de interrogación después del nombre del tipo, var optionalInteger: Int?
. [83] Las variables o constantes que están marcadas como opcionales tienen un valor del tipo subyacente o son nil
. Los tipos opcionales envuelven el tipo base, lo que da como resultado una instancia diferente. String
y String?
son tipos fundamentalmente diferentes, el primero es de tipo String
mientras que el segundo es un Optional
que puede contener algún String
valor.
Para acceder al valor que se encuentra dentro, suponiendo que no sea nulo, se debe desenvolver para exponer la instancia que se encuentra dentro. Esto se realiza con el !
operador:
deje que miValor = unaInstanciaOpcional !.algunMetodo ( )
En este caso, el !
operador desenvuelve anOptionalInstance
para exponer la instancia interna, lo que permite que se realice la llamada al método en ella. Si anOptionalInstance
es nulo, se produce un error de puntero nulo y se termina el programa. Esto se conoce como desenrollado forzado. Los opcionales se pueden desenrollar de forma segura mediante el encadenamiento opcional , que primero prueba si la instancia es nula y luego la desenrolla si no es nula:
deje que miValor = unaInstanciaOpcional ?.algunMetodo ( )
En este caso, el tiempo de ejecución solo invoca someMethod
si anOptionalInstance
no es nulo, lo que suprime el error. ?
Se debe colocar un después de cada propiedad opcional. Si alguna de estas propiedades es nula, la expresión completa se evalúa como nula. El origen del término encadenamiento proviene del caso más común en el que se encadenan varias llamadas a métodos/obtentores. Por ejemplo:
deje que unInquilino = unEdificio .listaInquilinos [ 5 ] deje que suArrendamiento = unInquilino .detallesDeArrendamiento deje que suArrendamientoInicio = suArrendamiento ? .fechaInicio
se puede reducir a:
deje que leaseStart = aBuilding .inquilinoList [ 5 ] .arrendamientoDetalles ? .fechaInicio
El uso de opcionales por parte de Swift permite al compilador utilizar el despacho estático porque la acción de desenrollado se llama en una instancia definida (el contenedor), en lugar de ocurrir en un sistema de despacho en tiempo de ejecución.
En muchos lenguajes orientados a objetos, los objetos se representan internamente en dos partes. El objeto se almacena como un bloque de datos colocado en el montón , mientras que el nombre (o "identificador") de ese objeto se representa mediante un puntero . Los objetos se pasan entre métodos copiando el valor del puntero, lo que permite que cualquier persona con una copia pueda acceder a los mismos datos subyacentes en el montón. Por el contrario, los tipos básicos, como los números enteros y los valores de punto flotante, se representan directamente; el identificador contiene los datos, no un puntero a ellos, y esos datos se pasan directamente a los métodos mediante copia. Estos estilos de acceso se denominan paso por referencia en el caso de los objetos y paso por valor para los tipos básicos.
Ambos conceptos tienen sus ventajas y desventajas. Los objetos son útiles cuando los datos son grandes, como la descripción de una ventana o el contenido de un documento. En estos casos, el acceso a esos datos se proporciona copiando un valor de 32 o 64 bits, en lugar de copiar una estructura de datos completa. Sin embargo, los valores más pequeños, como los números enteros, tienen el mismo tamaño que los punteros (normalmente ambos son una palabra ), por lo que no hay ninguna ventaja en pasar un puntero en lugar de pasar el valor.
Swift ofrece soporte integrado para objetos que utilizan semánticas de paso por referencia o de paso por valor, la primera utilizando la class
declaración y la segunda utilizando struct
. Las estructuras en Swift tienen casi todas las mismas características que las clases: métodos, implementación de protocolos y uso de los mecanismos de extensión. Por esta razón, Apple denomina a todos los datos de manera genérica como instancias , en lugar de objetos o valores. Sin embargo, las estructuras no admiten la herencia. [84]
El programador es libre de elegir qué semántica es más apropiada para cada estructura de datos en la aplicación. Las estructuras más grandes, como las ventanas, se definirían como clases, lo que permitiría pasarlas como punteros. Las estructuras más pequeñas, como un punto 2D, se pueden definir como estructuras, que se pasarán por valor y permitirán el acceso directo a sus datos internos sin indirección ni recuento de referencias. La mejora del rendimiento inherente al concepto de paso por valor es tal que Swift utiliza estos tipos para casi todos los tipos de datos comunes, incluidos Int
y Double
, y los tipos normalmente representados por objetos, como String
y Array
. [84] El uso de tipos de valor también puede dar como resultado mejoras significativas en el rendimiento en las aplicaciones de usuario. [85]
Array
, Dictionary
y Set
todos utilizan la función de copia al escribir, de modo que sus datos se copian solo si y cuando el programa intenta cambiar un valor en ellos. Esto significa que los diversos métodos de acceso tienen lo que en efecto es un puntero al mismo almacenamiento de datos. Por lo tanto, mientras que los datos se almacenan físicamente como una instancia en la memoria, a nivel de la aplicación, estos valores están separados y la separación física se aplica mediante la función de copia al escribir solo si es necesario. [86]
Las extensiones añaden nuevas funciones a un tipo existente, sin necesidad de crear subclases o incluso tener acceso al código fuente original. Las extensiones pueden añadir nuevos métodos, inicializadores, propiedades calculadas, subíndices y conformidades de protocolo. [87] Un ejemplo podría ser añadir un corrector ortográfico al String
tipo base, lo que significa que todas las instancias de String
en el programa obtienen la capacidad de realizar la corrección ortográfica. El sistema también se utiliza ampliamente como técnica organizativa, lo que permite reunir el código relacionado en extensiones similares a bibliotecas.
Las extensiones se declaran con la extension
palabra clave.
estructura Rectángulo { dejar ancho : Doble dejar altura : Doble}extensión Rectángulo { var área : Doble { devolver altura * ancho }}
Los protocolos prometen que un tipo particular implementa un conjunto de métodos o propiedades, lo que significa que otras instancias del sistema pueden llamar a esos métodos en cualquier instancia que implemente ese protocolo. Esto se usa a menudo en los lenguajes orientados a objetos modernos como sustituto de la herencia múltiple , aunque los conjuntos de características no son completamente similares.
En Objective-C y la mayoría de los demás lenguajes que implementan el concepto de protocolo, es responsabilidad del programador asegurarse de que los métodos requeridos se implementen en cada clase. [88] Swift agrega la capacidad de agregar estos métodos mediante extensiones y usar programación genérica (genéricos) para implementarlos. Combinados, estos permiten que los protocolos se escriban una vez y admitan una amplia variedad de instancias. Además, el mecanismo de extensión se puede utilizar para agregar conformidad con el protocolo a un objeto que no incluye ese protocolo en su definición. [89]
Por ejemplo, un protocolo podría declararse llamado Printable
, lo que garantiza que las instancias que se ajustan al protocolo implementen una description
propiedad y un printDetails()
requisito de método:
// Definir un protocolo llamado Printable protocol Printable { var description : String { get } // Un requisito de propiedad de solo lectura func printDetails () // Un requisito de método }
Este protocolo ahora puede ser adoptado por otros tipos:
// Adoptar el protocolo Printable en una clase class MyClass : Printable { var description : String { return "Una instancia de MyClass" } func printDetails () { print ( descripción ) } }
Las extensiones se pueden utilizar para agregar conformidad con el protocolo a los tipos. Los protocolos en sí también se pueden ampliar para proporcionar implementaciones predeterminadas de sus requisitos. Los adoptantes pueden definir sus propias implementaciones o pueden utilizar la implementación predeterminada:
extensión Printable { // Todas las instancias de Printable recibirán esta implementación, o pueden definir la suya propia. func printDetails () { print ( description ) } }// Bool ahora se ajusta a Printable y hereda la implementación de printDetails() anterior. extension Bool : Printable { var description : String { return "Una instancia de Bool con valor: \( self ) " }}
En Swift, como en muchos lenguajes modernos que admiten interfaces, los protocolos se pueden usar como tipos, lo que significa que las variables y los métodos se pueden definir por protocolo en lugar de por su tipo específico:
func getSomethingPrintable () -> cualquier Imprimible { devuelve verdadero }var someSortOfPrintableInstance = getSomethingPrintable () imprimir ( someSortOfPrintableInstance . descripción )// Imprime "Una instancia de Bool con valor: verdadero"
No importa cuál someSortOfPrintableInstance
sea el tipo concreto de , el compilador se asegurará de que se ajuste al protocolo y, por lo tanto, este código sea seguro. Esta sintaxis también significa que las colecciones también pueden basarse en protocolos, como let printableArray = [any Printable]
.
Tanto las extensiones como los protocolos se utilizan ampliamente en la biblioteca estándar de Swift; en Swift 5.9, aproximadamente el 1,2 por ciento de todos los símbolos dentro de la biblioteca estándar eran protocolos, y otro 12,3 por ciento eran requisitos de protocolo o implementaciones predeterminadas. [90] Por ejemplo, Swift usa extensiones para agregar el Equatable
protocolo a muchos de sus tipos básicos, como cadenas y matrices, lo que permite compararlos con el ==
operador. El Equatable
protocolo también define esta implementación predeterminada:
func !=< T : Ecuacional >( lhs : T , rhs : T ) -> Bool
Esta función define un método que funciona en cualquier instancia que cumpla con Equatable
, siempre que se utilice un operador de no igual . Cualquier instancia, clase o estructura obtiene automáticamente esta implementación simplemente al cumplir con Equatable
. [91]
Los protocolos, las extensiones y los genéricos se pueden combinar para crear API sofisticadas. Por ejemplo, las restricciones permiten que los tipos adopten protocolos o métodos de manera condicional según las características del tipo que los adopta. Un caso de uso común puede ser agregar un método a los tipos de colección solo cuando los elementos contenidos en la colección son Equatable
:
extensión Matriz donde Elemento : Equatable { // allEqual estará disponible solo en instancias de Array que contengan elementos Equatable. func allEqual () -> Bool { for element in self { if element != self . first { return false } } return true } }
Swift 5.5 introdujo la concurrencia estructurada en el lenguaje. [92] La concurrencia estructurada utiliza una sintaxis Async/await similar a la de Kotlin, JavaScript y Rust. Una función async se define con la async
palabra clave después de la lista de parámetros. Cuando se llama a una función async, la await
palabra clave debe escribirse antes de la función para indicar que la ejecución se suspenderá potencialmente mientras se llama a la función. Mientras una función está suspendida, el programa puede ejecutar alguna otra función concurrente en el mismo programa. Esta sintaxis permite a los programas señalar claramente los posibles puntos de suspensión y evitar una versión de la Pirámide de la perdición (programación) causada por el uso previamente generalizado de devoluciones de llamadas de cierre. [93]
func downloadText ( name : String ) async -> String { let result = // ... algún código de descarga asincrónica ... return result }deje que el texto = espere a descargarTexto ( "texto1" )
La async let
sintaxis permite ejecutar múltiples funciones en paralelo. await
Se utiliza nuevamente para marcar el punto en el que el programa se suspenderá para esperar la finalización de las async
funciones llamadas anteriormente.
// Cada una de estas llamadas a downloadText se ejecutará en paralelo. async let text1 = downloadText ( name : "text1" ) async let text2 = downloadText ( name : "text2" ) async let text3 = downloadText ( name : "text3" )let textToPrint = await [ text1 , text2 , text3 ] // Suspende hasta que hayan regresado las tres llamadas downloadText. print ( textToPrint )
Se pueden crear tareas y grupos de tareas explícitamente para crear una cantidad dinámica de tareas secundarias durante el tiempo de ejecución:
deje que taskHandle = Task { espere downloadText ( nombre : "someText" ) }deje que resultado = espere taskHandle . valor
Swift utiliza el modelo Actor para aislar el estado mutable, lo que permite que diferentes tareas muten el estado compartido de manera segura. Los actores se declaran con la actor
palabra clave y son tipos de referencia, como las clases. Solo una tarea puede acceder al estado mutable de un actor al mismo tiempo. Los actores pueden acceder y mutar su propio estado interno libremente, pero el código que se ejecuta en tareas separadas debe marcar cada acceso con la await
palabra clave para indicar que el código puede suspenderse hasta que otras tareas terminen de acceder al estado del actor.
Directorio de actores { var names : [ String ] = [] func add ( nombre : String ) { nombres.append ( nombre ) } } deje que el directorio = Directorio ()// El código se suspende hasta que otras tareas terminen de acceder al actor. await directory . add ( name : "Tucker" ) print ( await directory . names )
En los sistemas Apple, Swift utiliza el mismo entorno de ejecución que el sistema Objective-C existente , pero requiere iOS 7 o macOS 10.9 o superior. También depende de Grand Central Dispatch . [94] El código Swift y Objective-C se pueden utilizar en un programa y, por extensión, también C y C++. A partir de Swift 5.9, el código C++ se puede utilizar directamente desde el código Swift. [95] En el caso de Objective-C, Swift tiene un acceso considerable al modelo de objetos y se puede utilizar para subclasificar, extender y utilizar el código Objective-C para proporcionar soporte de protocolo. [96] Lo inverso no es cierto: una clase Swift no se puede subclasificar en Objective-C. [97]
Para facilitar el desarrollo de dichos programas y la reutilización del código existente, Xcode 6 y versiones posteriores ofrecen un sistema semiautomatizado que crea y mantiene un encabezado de puente para exponer el código Objective-C a Swift. Esto toma la forma de un archivo de encabezado adicional que simplemente define o importa todos los símbolos Objective-C que necesita el código Swift del proyecto. En ese punto, Swift puede hacer referencia a los tipos, funciones y variables declarados en esas importaciones como si estuvieran escritos en Swift. El código Objective-C también puede usar código Swift directamente, importando un archivo de encabezado mantenido automáticamente con declaraciones Objective-C de los símbolos Swift del proyecto. Por ejemplo, un archivo Objective-C en un proyecto mixto llamado "MyApp" podría acceder a clases o funciones Swift con el código #import "MyApp-Swift.h"
. Sin embargo, no todos los símbolos están disponibles a través de este mecanismo: el uso de características específicas de Swift como tipos genéricos, tipos opcionales no objeto, enumeraciones sofisticadas o incluso identificadores Unicode pueden hacer que un símbolo sea inaccesible desde Objective-C. [98]
Swift también tiene un soporte limitado para los atributos , metadatos que lee el entorno de desarrollo y que no necesariamente forman parte del código compilado. Al igual que Objective-C, los atributos utilizan la @
sintaxis, pero el conjunto disponible actualmente es pequeño. Un ejemplo es el @IBOutlet
atributo, que marca un valor dado en el código como una salida , disponible para su uso dentro de Interface Builder (IB). Una salida es un dispositivo que vincula el valor de la visualización en pantalla a un objeto en el código.
En sistemas que no son de Apple, Swift no depende de un entorno de ejecución Objective-C ni de otras bibliotecas de sistema de Apple; un conjunto de implementaciones de Swift "Corelib" las reemplazan. Estas incluyen una "swift-corelibs-foundation" para reemplazar a Foundation Kit , una "swift-corelibs-libdispatch" para reemplazar a Grand Central Dispatch y una "swift-corelibs-xctest" para reemplazar a las API XCTest de Xcode . [99]
A partir de 2019, con Xcode 11, Apple también agregó un nuevo paradigma de interfaz de usuario importante llamado SwiftUI. SwiftUI reemplaza el antiguo paradigma de Interface Builder con un nuevo paradigma de desarrollo declarativo. [100]
Swift utiliza el conteo automático de referencias (ARC) para administrar la memoria . Cada instancia de una clase o cierre mantiene un recuento de referencias que lleva un registro continuo de la cantidad de referencias que el programa mantiene. Cuando este recuento llega a 0, la instancia se desasigna. Esta desasignación automática elimina la necesidad de un recolector de elementos no utilizados, ya que las instancias se desasignan tan pronto como ya no son necesarias.
Un ciclo de referencia fuerte puede ocurrir si dos instancias hacen referencia fuerte entre sí (por ejemplo, A hace referencia a B, B hace referencia a A). Dado que el recuento de referencias de ninguna de las instancias puede llegar a cero, ninguna de ellas se desasigna, lo que da como resultado una pérdida de memoria . Swift proporciona las palabras clave weak
y unowned
para evitar ciclos de referencia fuertes. Estas palabras clave permiten que se haga referencia a una instancia sin incrementar su recuento de referencias. weak
Las referencias deben ser variables opcionales, ya que pueden cambiar y convertirse en nil
. [101] Intentar acceder a un unowned
valor que ya se ha desasignado da como resultado un error de tiempo de ejecución.
Un cierre dentro de una clase también puede crear un ciclo de referencia fuerte al capturar autorreferencias. Las autorreferencias que se deben considerar débiles o sin propietario se pueden indicar mediante una lista de captura.
clase Persona { deje que el nombre sea una cadena débil var home : Home ? // Se define como una referencia débil para romper el ciclo de referencia. Las referencias débiles no incrementan el recuento de referencias de la instancia a la que hacen referencia. init ( nombre : Cadena ) { yo.nombre = nombre } deinit { print ( "Desinicializado \( nombre ) " ) }}clase Inicio { deje dirección : cadena var propietario : Persona ? init ( dirección : String , propietario : Persona ?) { auto.dirección = dirección yo mismo.propietario = propietario } deinit { print ( "Desinicializado \( dirección ) " ) }}var stacy : Persona ? = Persona ( nombre : "Stacy" )var house21b : Hogar ? = Hogar ( dirección : "21b Baker Street" , propietario : stacy )stacy ? .home = house21b // stacy y house42b ahora se refieren entre sí.stacy = nil // El recuento de referencias para stacy ahora es 1, porque house21b todavía mantiene una referencia a él.house21b = nil // El recuento de referencias de house21b cae a 0, lo que a su vez cae el recuento de stacy a 0 porque house21b fue la última instancia que tenía una fuerte referencia a stacy.// Impresiones:// Se desinicializó 21b Baker Street// Stacy desinicializada
Un elemento clave del sistema Swift es su capacidad de ser depurado limpiamente y ejecutado dentro del entorno de desarrollo, utilizando un bucle de lectura-evaluación-impresión (REPL), lo que le otorga propiedades interactivas más en común con las capacidades de scripting de Python que los lenguajes de programación de sistemas tradicionales . El REPL se mejora aún más con los patios de juegos , vistas interactivas que se ejecutan dentro del entorno Xcode o la aplicación Playgrounds que responden a los cambios de código o depurador sobre la marcha. [102] Los patios de juegos permiten a los programadores agregar código Swift junto con documentación de Markdown. Los programadores pueden recorrer el código y agregar puntos de interrupción usando LLDB ya sea en una consola o un IDE como Xcode.
Swift se considera un lenguaje de programación de la familia C y es similar a C en varios aspectos:
+
tienen un comportamiento ligeramente diferente. Por ejemplo, en Swift, se +
utilizan trampas en caso de desbordamiento, mientras que &+
se utiliza para indicar el comportamiento similar al de C de envoltura en caso de desbordamiento.===
, para comprobar si dos elementos de datos hacen referencia al mismo objeto .while
, if
, y switch
son similares, pero tienen funciones extendidas, por ejemplo, a, switch
que acepta casos no enteros while
y if
admite la coincidencia de patrones y el desenrollado condicional de opcionales, for
utiliza la sintaxis.for i in 1...10
También tiene similitudes con Objective-C:
Int, UInt, Float, Double
self
en los métodos de clase está la clase en la que se llamó al método.for
....in
Las diferencias con Objective-C incluyen:
;
), aunque estos deben usarse para permitir más de una declaración en una línea.i = 0
en lugar de i == 0
(que genera un error en tiempo de compilación).break
sentencias en switch
bloques. Los casos individuales no pasan al siguiente caso a menos que fallthrough
se utilice la sentencia.&+
, &-
, y . Las propiedades y están definidas en Swift para todos los tipos de enteros y se pueden utilizar para comprobar de forma segura si &*
hay desbordamientos potenciales, en lugar de depender de constantes definidas para cada tipo en bibliotecas externas.&/
&%
min
max
if
y while
, que permite la omisión de llaves alrededor de la declaración, no es compatible.for (int i = 0; i < c; i++)
, que es propensa a errores de un dígito , no es compatible (desde Swift 3 en adelante). [104]i++
, --i
...) no son compatibles (desde Swift 3 en adelante), más aún porque las declaraciones de estilo C for
tampoco son compatibles desde Swift 3 en adelante. [105]Dado que Swift puede ejecutarse en Linux, a veces también se utiliza como lenguaje del lado del servidor. [106] Ya se han desarrollado algunos marcos web, como Kitura (ahora descontinuado) de IBM , Perfect y Vapor .
Apple también ha iniciado un grupo de trabajo oficial sobre "API de servidor", [107] en el que los miembros de la comunidad de desarrolladores de Swift desempeñan un papel central. [108]
Existe una segunda implementación gratuita de Swift dirigida a Cocoa , la Infraestructura de lenguaje común de Microsoft ( .NET Framework , ahora .NET ) y la plataforma Java y Android como parte del compilador de elementos de RemObjects Software . [109]
Se han portado subconjuntos de Swift a plataformas adicionales, como Arduino [110] y Mac OS 9. [ 111]
{{cite web}}
: Falta o está vacío |title=
( ayuda )Swift es un sistema propietario y cerrado: está totalmente controlado por Apple y no existe ninguna implementación de código abierto.
Puedes imaginar que muchos de nosotros queremos que sea de código abierto y parte de LLVM, pero la discusión aún no ha sucedido y no sucederá durante algún tiempo.
El lenguaje Swift es el producto del esfuerzo incansable de un equipo de expertos en lenguajes, gurús de la documentación, ninjas de la optimización de compiladores y un grupo interno de pruebas internas increíblemente importante que brindó comentarios para ayudar a refinar y probar ideas. Por supuesto, también se benefició enormemente de las experiencias ganadas con mucho esfuerzo por muchos otros lenguajes en el campo, tomando ideas de Objective-C, Rust, Haskell, Ruby, Python, C#, CLU y muchos otros para enumerarlos.
Comencé a trabajar en el lenguaje de programación Swift en julio de 2010. Implementé gran parte de la estructura básica del lenguaje, y solo unas pocas personas sabían de su existencia. Algunas otras personas (increíbles) comenzaron a contribuir en serio a fines de 2011, y se convirtió en un foco principal para el grupo de herramientas para desarrolladores de Apple en julio de 2013 [...] tomando ideas de
Objective-C
, Rust, Haskell, Ruby, Python, C#, CLU y muchos otros para enumerarlos.
{{cite web}}
: |last=
tiene nombre genérico ( ayuda ){{cite web}}
: |last=
tiene nombre genérico ( ayuda )