Swift es un lenguaje de programación compilado de alto nivel , de propósito general y multiparadigma , desarrollado por Apple Inc. y la comunidad de código abierto . Swift compila en código máquina, ya que es un compilador basado en LLVM . Swift se lanzó por primera vez en junio de 2014, [11] y la cadena de herramientas Swift se envió en Xcode desde la versión 6, lanzada en 2014.
Apple pretendía que Swift soportara muchos conceptos centrales asociados con Objective-C , en particular el envío dinámico , el enlace tardío generalizado , la programación extensible y características similares, pero de una manera "más segura", facilitando la detección de errores de software ; Swift tiene funciones que abordan algunos errores de programación comunes , como la desreferenciación de puntero nulo , y proporciona azúcar sintáctico para ayudar a evitar la pirámide de la perdición . Swift apoya el concepto de extensibilidad de protocolo , un sistema de extensibilidad que se puede aplicar a tipos, estructuras y clases , lo 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 clases de tipos ). ). [13]
Swift se presentó en la Conferencia Mundial de Desarrolladores de 2014 (WWDC) de Apple. [14] Se sometió a una actualización a la versión 1.2 durante 2014 y a una actualización importante a Swift 2 en la WWDC 2015. Inicialmente un lenguaje propietario , 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 través de la versión 3.0, la sintaxis de Swift pasó por una evolución significativa, y el equipo central se centró en la estabilidad del código fuente en 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 Apple, lo que permitió incorporar el tiempo de ejecución de Swift en los sistemas operativos de Apple. Es compatible con Swift 4. [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 hace posible 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 de lenguajes para concurrencia y código asincrónico , introduciendo en particular una versión única del modelo de actor . [22]
La versión actual, 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]
El desarrollo de Swift comenzó en julio de 2010 por Chris Lattner , con la eventual colaboración de muchos otros programadores de Apple . Swift fue motivado por la necesidad de reemplazar el anterior lenguaje de programación Objective-C de Apple , que se había mantenido prácticamente sin cambios desde principios de la década de 1980 y carecía de características de lenguaje moderno. 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 Apple Worldwide Developers Conference (WWDC) se convirtió en la primera aplicación lanzada públicamente escrita con Swift. [24] Se lanzó una versión beta del lenguaje de programación a los desarrolladores registrados de Apple en la conferencia, pero la compañía no prometió que la versión final de Swift sería un código fuente compatible con la versión de prueba. Apple planeó poner a disposición convertidores de código fuente si fuera necesario para el lanzamiento completo. [24]
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. [25]
Swift alcanzó el hito 1.0 el 9 de septiembre de 2014, con Gold Master de Xcode 6.0 para iOS . [26] Swift 1.1 se lanzó el 22 de octubre de 2014, junto con el lanzamiento de Xcode 6.1. [27] Swift 1.2 se lanzó el 8 de abril de 2015, junto con Xcode 6.3. [28] Swift 2.0 se anunció en la WWDC 2015 y estuvo disponible para publicar aplicaciones en la App Store el 21 de septiembre de 2015. [29] Swift 3.0 se lanzó el 13 de septiembre de 2016. [30] Swift 4.0 se lanzó en septiembre 19 de 2017. [31] Swift 4.1 se lanzó el 29 de marzo de 2018. [32]
Swift ganó el primer lugar como lenguaje de programación más querido en la encuesta para desarrolladores de Stack Overflow 2015 [33] y el segundo lugar en 2016. [34]
El 3 de diciembre de 2015, el lenguaje Swift, las bibliotecas de soporte, el depurador y el administrador de paquetes fueron de código abierto bajo la licencia Apache 2.0 con una excepción de biblioteca en tiempo de ejecución, [35] 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 ellos mismos e incluso crear solicitudes de extracción para contribuir con el código 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. [36] [37] [38] Swift Sandbox quedó obsoleto en enero de 2018. [39]
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 3D similar a un videojuego que proporciona retroalimentación cuando las líneas de código se colocan en un orden determinado y se ejecutan. [40] [41] [42]
En enero de 2017, Chris Lattner anunció su salida de Apple para ocupar un nuevo puesto en Tesla Motors , y el papel principal del proyecto Swift recayó en el veterano del equipo Ted Kremenek. [43] [44]
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. [45]
Las descargas oficiales para la distribución Ubuntu de Linux han estado disponibles desde Swift 2.2, y se han agregado más distribuciones desde Swift 5.2.4, CentOS y Amazon Linux. [46] También existe un SDK no oficial y un paquete de cadena de herramientas nativo para Android. [47] [48]
Las plataformas que admite Swift son los sistemas operativos de Apple ( Darwin , iOS , iPadOS , macOS , tvOS , watchOS ), Linux , Windows y Android . [49] [50]
Un aspecto clave del diseño de Swift es su capacidad para interoperar con la enorme cantidad de código Objective-C existente desarrollado para productos Apple durante las décadas anteriores, como Cocoa y los marcos Cocoa Touch . En las plataformas Apple, [51] se vincula con la biblioteca de tiempo de ejecución Objective-C , que permite ejecutar código C , Objective-C , C++ y Swift dentro de un programa. [52]
Swift es un lenguaje de programación de propósito general que emplea conceptos teóricos de lenguajes de programación modernos y se esfuerza por 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 lenguaje de desarrollo principal en las plataformas Apple.
Swift fue diseñado para ser seguro y amigable para los nuevos programadores sin sacrificar la velocidad. De forma 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 los 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 manejar valores nulos de forma explícita y segura. Se pueden escribir programas simultáneos utilizando la sintaxis async/await y los actores aíslan el estado mutable compartido para eliminar las carreras de datos. [67] [68]
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. [69] Alternativamente, al atributo se le puede aplicar una estructura, clase o declaración de enumeración para indicar que contiene el punto de entrada del programa. [70]@main
"¡Hola, mundo!" de Swift. programa es:
imprimir ( "¡Hola mundo!" )
La función utilizada aquí está incluida en la biblioteca estándar de Swift, que está disponible para todos los programas sin la necesidad de importar módulos externos. Las declaraciones en Swift no tienen que terminar con un punto y coma; sin embargo, se requieren puntos y coma para separar varias declaraciones escritas en la misma línea. Los comentarios de una sola línea comienzan y continúan hasta el final de la línea actual. Los comentarios de varias líneas están contenidos en 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. [69]print(_:separator:terminator:)
//
/*
*/
let
var
let highScoreThreshold = 1000 // Una constante de tipo Int. El tipo se dedujo en función del valor proporcionado.var currentScore = 980 // Una variable de tipo Int.currentScore = 1200 // El valor de las variables puede cambiar con el tiempo.let playerMessage : String // Una constante con tipo explícito String.si puntuación actual > Umbral de puntuación alta { playerMessage = "¡Eres un jugador de primer nivel!"} demás { playerMessage = "Más suerte la próxima vez."}print ( playerMessage ) // Imprime "¡Eres un jugador destacado!"
El flujo de control en Swift se gestiona con sentencias if-else , guard y switch , junto con bucles while y for-in . Las declaraciones if toman un parámetro booleano y ejecutan el cuerpo de la declaración if si la condición es verdadera; de lo contrario, ejecuta el else
cuerpo opcional. syntax proporciona azúcar sintáctico para verificar la existencia de un valor opcional y desenvolverlo al mismo tiempo.if-let
deja que algún número = 42if someNumber % 2 == 0 { // Usa el operador de resto para encontrar el resto de someNumber dividido por 2. print ( " \( algúnNumber ) es par. " )} demás { print ( " \( algúnNumber ) es impar." )}// Imprime "42 es par".
Las funciones se definen con la
palabra clave. Los parámetros de función pueden tener nombres que permitan que las llamadas a funciones se lean como frases. Un guión bajo antes del nombre del parámetro permite omitir la etiqueta del argumento en el sitio de llamada. Las funciones pueden utilizar tuplas para devolver varios datos a la vez.func
func constructSaludo ( para nombre : Cadena ) -> Cadena { devolver "¡Hola \( nombre ) !"}let saludo = constructSaludo ( para : "Craig" )print ( saludo ) // Imprime "¡Hola Craig!"
Las funciones y funciones anónimas conocidas como cierres se pueden asignar a propiedades y pasar por el programa como cualquier otro valor.
func divideByTwo ( _ aNum : Int ) -> Int { devolver unNum / 2}func multiplicarPorDos ( _ aNum : Int ) -> Int { devolver unNum * 2}let mathOperation = multiplicar por dosprint ( operaciónmatemática ( 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 . guard
La else
cláusula debe salir del control del bloque de código en el que else
aparece la declaración. guard
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 empaquetar de un valor opcional que se garantiza que no será nulo durante el resto del alcance adjunto.guard
func dividir ( numerador : Int ?, porDenominador denominador : Int ) - > Int ? { denominador de guardia ! = 0 más { print ( "No se puede dividir entre 0." ) retorno nulo } guardia deja numerador más { print ( "El numerador proporcionado es nulo." ) retorno nulo } devolver numerador / denominador}dejar resultado = dividir ( numerador : 3 , porDenominador : 0 )print ( "El resultado de la división es: \( resultado ) " )// Impresiones:// "No se puede dividir entre 0."// "El resultado de la división es: nulo."
switch
Las declaraciones comparan un valor con múltiples valores potenciales y luego ejecuta 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 fracasan 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. A continuación se muestra un ejemplo de un número entero que se compara con varios rangos potenciales:
deja que algún número = 42cambiar algún número {caso ..< 0 : print ( " \( algúnNúmero ) negativo." )caso 0 : print ( " \( algúnNumber ) es 0. " )caso 1 ... 9 : print ( " \( algúnNúmero ) mayor que 0, pero menor que 10." )por defecto : print ( " \( algúnNumber ) es mayor que 9. " )}// Imprime "42 es mayor que 9."
for-in
los bucles iteran sobre una secuencia de valores:
let nombres = [ "Will" , "Anna" , "Bart" ]para nombre en nombres { imprimir ( nombre )}// Impresiones:// Voluntad// Ana// Bart
while
los bucles se iteran siempre que la condición booleana dada se evalúe como true
:
// Suma todos los números del 1 al 5.var i = 1 resultado var = 0while i <= 5 { // El bucle realiza 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 autónomos de funcionalidad que pueden transmitirse y usarse en el código, [71] y también pueden usarse como funciones anónimas . Aquí hay unos ejemplos:
// El tipo de cierre, definido por sus valores de entrada y salida, se puede especificar fuera del cierre:let cierre1 : ( Int , Int ) -> Int = { arg1 , arg2 en devolver arg1 + arg2}// …o dentro de él:let cierre2 = { ( arg1 : Int , arg2 : Int ) -> Int en devolver arg1 + arg2}// En la mayoría de los casos, el compilador puede inferir automáticamente el tipo de retorno del cierre.let cierre3 = { arg1 : Int , arg2 : Int en devolver 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 una sola expresión pueden eliminar 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 número entero,// lo evalúa y utiliza el valor de retorno del cierre (un Int) como valor de retorno de la función.func foo ( barra de cierre : () -> Int ) -> Int { barra de retorno ()}// Sin sintaxis de cierre final:foo ( cierre : { retorno 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: [72]
// 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 { retorno baz ( barra ()) }// Sin cierres finales: foo ( bar : { return 1 }, baz : { x in return x + 1 })// Con 1 cierre final: foo ( bar : { return 1 }) { x in 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 abreviados de argumentos para cierres en línea, eliminando la necesidad de nombrar explícitamente todos los parámetros de cierres. [73] Se puede hacer referencia a los argumentos con los nombres $0, $1, $2, etc.:
let nombres = [ "Josephine" , "Steve" , "Chris" , "Barbara" ]// el filtro llama al cierre dado para cada valor en nombres. // Los valores con un número de caracteres inferior a 6 se mantienen, los demás se eliminan. let shortNames = nombres . filtro { $0 . contar < 6 }imprimir ( nombres cortos ) // Imprime "["Steve", "Chris"]"
Los cierres pueden capturar valores de su ámbito circundante. El cierre se referirá a este valor capturado mientras exista el cierre:
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. devolver { $0 * múltiple } }let multiplicador = makeMultiplier ( withMultiple : 3 ) print ( multiplicador ( 3 )) // Imprime "9" print ( multiplicador ( 10 )) // Imprime "30"
String
La biblioteca estándar de Swift incluye tipos y compatibles 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 a \
se insertarán en la cadena literal adjunta: [74]
var currentScore = 980 print ( "Tu 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 carácter en "Swift" { imprimir ( carácter ) } // S // w // i // f // t
Cuando se importa el marco Foundation, Swift une de forma invisible el tipo String con NSString, la clase String comúnmente utilizada en Objective-C.
En Swift, los objetos invocables se definen mediante callAsFunction
. [75]
struct CallableStruct { valor var : Int func callAsFunction ( _ número : Int , escala : Int ) { print ( escala * ( número + valor )) } } let invocable = CallableStruct ( valor : 100 ) invocable ( 4 , escala : 2 ) invocable . callAsFunction ( 4 , escala : 2 ) // Ambas llamadas a funciones imprimen 208.
Swift admite cinco niveles de control de acceso para símbolos: open
, public
, internal
, fileprivate
y private
. A diferencia de muchos lenguajes orientados a objetos, estos controles de acceso ignoran las jerarquías de herencia : private
indica que un símbolo es accesible sólo en el ámbito inmediato , fileprivate
indica que es accesible sólo desde dentro del archivo, internal
indica que es accesible dentro del módulo que lo contiene, public
indica que es accesible desde cualquier módulo y open
(solo para clases y sus métodos) indica que la clase puede tener subclases fuera del módulo. [76]
Una característica importante en Swift son los tipos de opciones , que permiten que las referencias o 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. 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 Optional
enum. Para crear un número entero que acepte valores NULL, se usaría una declaración similar a var optionalInteger: Optional<Int>
. Al igual que en C#, [77] Swift también incluye azúcar sintáctico 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?
. [78] Las variables o constantes 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 tener algún String
valor.
Para acceder al valor interno, suponiendo que no sea nulo, se debe desenvolver para exponer la instancia interna. Esto se realiza con el !
operador:
let myValue = anOptionalInstance !. algún método ()
En este caso, el !
operador se desenvuelve anOptionalInstance
para exponer la instancia interna, permitiendo que se realice la llamada al método en ella. Si anOptionalInstance
es nulo, se produce un error de puntero nulo que finaliza el programa. Esto se conoce como desenvolvimiento forzado. Los opcionales se pueden desenvolver de forma segura usando un encadenamiento opcional que primero prueba si la instancia es nula y luego desenvuelvela si no es nula:
let myValue = anOptionalInstance ?. algún método ()
En este caso, el tiempo de ejecución llama someMethod
solo si anOptionalInstance
no es nulo, suprimiendo el error. Se ?
debe colocar una 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/captadores de métodos. Por ejemplo:
let aInquilino = aBuilding . lista de inquilinos [ 5 ] let itsLease = aTenant . LeaseDetails let LeaseStart = su contrato de arrendamiento ?. fecha de inicio
se puede reducir a:
let leaseStart = aBuilding . Lista de inquilinos [ 5 ]. detalles del contrato de arrendamiento ?. fecha de inicio
El uso de opciones opcionales por parte de Swift permite que el compilador use el envío estático porque la acción de desempaquetado se llama en una instancia definida (el contenedor), en lugar de ocurrir en un sistema de envío 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 cualquiera que tenga una copia pueda acceder a los mismos datos subyacentes en el montón. Por el contrario, los tipos básicos como números enteros y 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 objetos y paso por valor para 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 usan semántica de paso por referencia o de paso por valor, el primero usando la class
declaración y el segundo usando struct
. Las estructuras en Swift tienen casi todas las mismas características que las clases: métodos, implementación de protocolos y uso de mecanismos de extensión. Por esta razón, Apple denomina genéricamente todos los datos instancias , frente a objetos o valores. Sin embargo, las estructuras no admiten la herencia. [79]
El programador es libre de elegir qué semántica es más apropiada para cada estructura de datos de 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 pasarán por valor y permitirán el acceso directo a sus datos internos sin direccionamiento indirecto ni recuento de referencias. La mejora de rendimiento inherente al concepto de paso por valor es tal que Swift usa estos tipos para casi todos los tipos de datos comunes, incluidos Int
y Double
, y tipos normalmente representados por objetos, como String
y Array
. [79] El uso de tipos de valores también puede dar lugar a mejoras significativas en el rendimiento de las aplicaciones de usuario. [80]
Array
, Dictionary
y Set
todos utilizan copia en escritura para que sus datos se copien solo si el programa intenta cambiar un valor en ellos. Esto significa que los distintos descriptores de acceso tienen lo que en realidad es un puntero al mismo almacenamiento de datos. Entonces, si bien los datos se almacenan físicamente como una instancia en la memoria, en el nivel de la aplicación, estos valores están separados y la separación física se aplica mediante copia en escritura solo si es necesario. [81]
Las extensiones agregan nueva funcionalidad a un tipo existente, sin la necesidad de crear subclases o incluso tener acceso al código fuente original. Las extensiones pueden agregar nuevos métodos, inicializadores, propiedades calculadas, subíndices y conformidades de protocolo. [82] Un ejemplo podría ser agregar un corrector ortográfico al String
tipo base, lo que significa que todas las instancias de String
en el programa obtienen la capacidad de corregir la ortografía. El sistema también se utiliza ampliamente como técnica organizativa, permitiendo que el código relacionado se recopile en extensiones similares a las de una biblioteca.
Las extensiones se declaran con la extension
palabra clave.
estructura rectángulo { dejar ancho : Doble dejar altura : Doble}extensión Rectángulo { área var : Doble { altura de retorno * 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 utiliza a menudo en los lenguajes modernos orientados a objetos como sustituto de la herencia múltiple , aunque los conjuntos de características no son del todo similares.
En Objective-C y en la mayoría de los demás lenguajes que implementan el concepto de protocolo, corresponde al programador asegurarse de que se implementen los métodos requeridos en cada clase. [83] Swift agrega la capacidad de agregar estos métodos usando extensiones y de usar programación genérica (generics) 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 de protocolo a un objeto que no incluye ese protocolo en su definición. [84]
Por ejemplo, se podría declarar un protocolo 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 Protocolo imprimible Imprimible { var descripción : Cadena { 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 Imprimible en una clase clase MiClase : Imprimible { var descripción : Cadena { return " Una instancia de MiClase" } func imprimirDetalles () { imprimir ( descripción ) } }
Se pueden utilizar extensiones para agregar conformidad de protocolo a los tipos. Los propios protocolos 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 Imprimible { // Todas las instancias Imprimibles recibirán esta implementación, o pueden definir la suya propia. func imprimirDetalles () { imprimir ( descripción ) } }// Bool ahora se ajusta a Printable y hereda la implementación printDetails() anterior. extensión Bool : Imprimible { var descripción : Cadena { return "Una instancia de Bool con valor: \( self ) " }}
En Swift, como 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 { retorno verdadero }var someSortOfPrintableInstance = getSomethingPrintable () imprimir ( algunoSortOfPrintableInstance . descripción )// Imprime "Una instancia de Bool con valor: verdadero"
No importa qué tipo concreto someSortOfPrintableInstance
sea, el compilador se asegurará de que cumpla con el 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. [85] 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 : Equatable >( lhs : T , rhs : T ) -> Bool
Esta función define un método que funciona en cualquier instancia conforme a Equatable
, proporcionando un operador distinto . Cualquier instancia, clase o estructura obtiene automáticamente esta implementación simplemente cumpliendo con Equatable
. [86]
Se pueden combinar protocolos, extensiones y genéricos para crear API sofisticadas. Por ejemplo, las restricciones permiten que los tipos adopten condicionalmente protocolos o métodos basados en 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 dentro de 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 { para elemento en uno mismo { si elemento != uno mismo . primero { return false } } return true } }
Swift 5.5 introdujo la concurrencia estructurada en el lenguaje. [87] La concurrencia estructurada utiliza una sintaxis Async/await similar a Kotlin, JavaScript y Rust. Una función asíncrona se define con la async
palabra clave después de la lista de parámetros. Al llamar a una función asíncrona, 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 simultánea en el mismo programa. Esta sintaxis permite a los programas señalar claramente 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. [88]
func downloadText ( nombre : String ) async -> String { let result = //... algún código de descarga asincrónica... devolver resultado }let text = esperar descargarTexto ( "texto1" )
La async let
sintaxis permite que se ejecuten múltiples funciones en paralelo. await
se utiliza nuevamente para marcar el punto en el que el programa se suspenderá para esperar a que se completen las async
funciones llamadas anteriormente.
// Cada una de estas llamadas a downloadText se ejecutará en paralelo. async let text1 = descargarTexto ( nombre : "texto1" ) async let text2 = descargarTexto ( nombre : "text2" ) async let text3 = descargarTexto ( nombre : "text3" )let textToPrint = await [ text1 , text2 , text3 ] // Se suspende hasta que hayan regresado las tres llamadas downloadText. imprimir ( texto para imprimir )
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:
let taskHandle = Tarea { espera descargarTexto ( nombre : "algúnTexto" ) }let result = await taskHandle . valor
Swift usa el modelo Actor para aislar el estado mutable, permitiendo 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 clases. Sólo 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 nombres : [ Cadena ] = [] func agregar ( nombre : Cadena ) { nombres . agregar ( nombre ) } }let directorio = Directorio ()// El código se suspende hasta que otras tareas terminen de acceder al actor. espera directorio . agregar ( nombre : "Tucker" ) imprimir ( esperar directorio . nombres )
En los sistemas Apple, Swift usa el mismo tiempo 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 . [89] El código Swift y Objective-C se puede 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. [90] En el caso de Objective-C, Swift tiene un acceso considerable al modelo de objetos y puede usarse para subclasificar, ampliar y usar código Objective-C para proporcionar soporte de protocolo. [91] Lo contrario no es cierto: una clase Swift no puede subclasificarse en Objective-C. [92]
Para ayudar al desarrollo de dichos programas y la reutilización del código existente, Xcode 6 y superiores ofrecen un sistema semiautomático que construye y mantiene un encabezado 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 declaradas en esas importaciones como si estuvieran escritas 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 que no son de objeto, enumeraciones sofisticadas o incluso identificadores Unicode pueden hacer que un símbolo sea inaccesible desde Objective-C. [93]
Swift también tiene soporte limitado para 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 determinado 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 código.
En sistemas que no son de Apple, Swift no depende de un tiempo de ejecución de Objective-C ni de otras bibliotecas del sistema de Apple; un conjunto de implementaciones Swift "Corelib" las reemplazan. Estos incluyen un "swift-corelibs-foundation" que reemplaza al Foundation Kit , un "swift-corelibs-libdispatch" que reemplaza al Grand Central Dispatch y un "swift-corelibs-xctest" que reemplaza al XCTest. API de Xcode . [94]
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. [95]
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 mantiene un recuento continuo del número de referencias que mantiene el programa. Cuando este recuento llega a 0, la instancia se desasigna. Esta desasignación automática elimina la necesidad de un recolector de basura, ya que las instancias se desasignan tan pronto como ya no son necesarias.
Puede ocurrir un ciclo de referencia fuerte 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 genera una pérdida de memoria . Swift proporciona las palabras clave weak
y unowned
para evitar ciclos de referencia fuertes. Estas palabras clave permiten hacer 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
. [96] Intentar acceder a un unowned
valor que ya ha sido desasignado genera un error de tiempo de ejecución.
Un cierre dentro de una clase también puede crear un fuerte ciclo de referencia al capturar autorreferencias. Las autorreferencias que deben considerarse débiles o sin propietario se pueden indicar mediante una lista de captura.
clase Persona { let nombre : Cadena var débil inicio : Inicio ? // Definido 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 ) { ser . nombre = nombre } deinit { print ( "Desinicializado \( nombre ) " ) }}clase Inicio { dejar dirección : cadena propietario de var : ¿ Persona ? init ( dirección : Cadena , propietario : Persona ?) { ser . dirección = dirección ser . dueño = dueño } deinit { print ( "Desinicializado \( dirección ) " ) }}var stacy : ¿ Persona ? = Persona ( nombre : "Stacy" )var house21b : ¿ Inicio ? = Casa ( 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 tiene una referencia a ella.house21b = nil // el recuento de referencias de house21b cae a 0, lo que a su vez reduce el recuento de stacy a 0 porque house21b fue la última instancia que tenía una fuerte referencia a stacy.// Impresiones:// Desinicializado 21b Baker Street// Stacy desinicializada
Un elemento clave del sistema Swift es su capacidad para depurarse y ejecutarse limpiamente dentro del entorno de desarrollo, utilizando un bucle de lectura, evaluación e impresión (REPL), lo que le otorga propiedades interactivas más en común con las capacidades de secuencias de comandos de Python que con la programación del sistema tradicional. idiomas. El REPL se mejora aún más con áreas de juegos , vistas interactivas que se ejecutan dentro del entorno Xcode o la aplicación Playgrounds que responden a los cambios del código o del depurador sobre la marcha. [97] Playgrounds permite a los programadores agregar código Swift junto con documentación de rebajas. Los programadores pueden recorrer el código y agregar puntos de interrupción usando LLDB , ya sea en una consola o en 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, +
atrapa en caso de desbordamiento, mientras que &+
se usa para denotar el comportamiento tipo C de ajuste en caso de desbordamiento.===
para comprobar si dos elementos de datos se refieren al mismo objeto .while
, if
y switch
son similares, pero tienen funciones extendidas, por ejemplo, a switch
que toma casos no enteros while
y if
admite la coincidencia de patrones y desenvuelve opcionales condicionalmente, for
usa la sintaxis.for i in 1...10
También tiene similitudes con Objective-C:
Int, UInt, Float, Double
self
en métodos de clase es la clase en la que se llamó al método.for
... in
sintaxis de enumeración.Las diferencias con Objective-C incluyen:
;
), aunque deben usarse para permitir más de una declaración en una línea.i = 0
en lugar de i == 0
generar un error en tiempo de compilación.break
declaraciones en switch
bloques. Los casos individuales no pasan al siguiente caso a menos que fallthrough
se utilice la declaración.&+
,, y . Las propiedades y están definidas en Swift para todos los tipos de enteros y se pueden usar para verificar de forma segura posibles desbordamientos, 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 está respaldada.for (int i = 0; i < c; i++)
, que es propensa a errores uno por uno , no es compatible (desde Swift 3 en adelante). [99]i++
, --i
...) no son compatibles (desde Swift 3 en adelante), más aún porque for
las declaraciones de estilo C tampoco son compatibles desde Swift 3 en adelante. [100]Debido a que Swift puede ejecutarse en Linux, a veces también se utiliza como lenguaje del lado del servidor. [101] Algunos marcos web ya se han desarrollado, como Kitura de IBM (ahora descontinuado), Perfect y Vapor .
Apple también ha iniciado un grupo de trabajo oficial sobre "API de servidor", [102] en el que los miembros de la comunidad de desarrolladores de Swift desempeñan un papel central. [103]
Existe una segunda implementación gratuita de Swift dirigida a Cocoa , la infraestructura de lenguaje común de Microsoft ( .NET Framework , ahora .NET ) y las plataformas Java y Android como parte del compilador de elementos de RemObjects Software . [104]
Se han portado subconjuntos de Swift a plataformas adicionales, como Arduino [105] y Mac OS 9 . [106]
Swift es propietario y cerrado: está totalmente controlado por Apple y no existe una 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 ocurrido, y no lo hará por algún tiempo.
El lenguaje Swift es el producto del esfuerzo incansable de un equipo de expertos en lenguaje, gurús de la documentación, ninjas de optimización de compiladores y un grupo interno increíblemente importante de pruebas internas que brindaron comentarios para ayudar a refinar y probar ideas.
Por supuesto, también se benefició enormemente de las experiencias ganadas con esfuerzo por muchos otros lenguajes en el campo, extrayendo 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 conocían su existencia.
Algunas otras personas (increíbles) comenzaron a contribuir seriamente a finales de 2011, y se convirtió en un foco importante para el grupo de herramientas de desarrollo de Apple en julio de 2013 [...] extrayendo ideas de
Objective-C
, Rust, Haskell, Ruby, Python, C#, CLU y muchos otros para enumerarlos.
{{cite web}}
: |last=
tiene nombre genérico ( ayuda )