-
Novedades de Swift
Únase para una actualización sobre Swift. Hablaremos sobre las mejoras del flujo de trabajo para que sea más productivo y sobre las API de biblioteca nuevas y modernizadas para tareas de programación fundamentales. Mostraremos ejemplos de adopción de Swift en más capas de la pila de software. Por último, exploraremos nuevas funcionalidades del lenguaje para mejorar la accesibilidad de la concurrencia y lograr el máximo rendimiento cuando lo necesites.
Capítulos
- 0:00 - Introducción y agenda
- 0:48 - Actualizaciones de swiftlang
- 3:06 - Flujo de trabajo de desarrollo: Escribir código
- 4:40 - Flujo de trabajo de desarrollo: Desarrollo
- 7:36 - Flujo de trabajo de desarrollo: Depuración
- 9:14 - Bibliotecas: Subproceso
- 10:45 - Bibliotecas: Base
- 12:31 - Bibliotecas: Observación
- 14:13 - Bibliotecas: Prueba
- 16:08 - Swift en la pila: Swift integrado
- 18:00 - Swift en la pila: Seguridad
- 19:37 - Swift en la pila: Servidor
- 23:23 - Swift en la pila: Plataformas
- 26:11 - Evolución del lenguaje: Rendimiento
- 30:28 - Evolución del lenguaje: Concurrencia
- 37:15 - Conclusión
Recursos
Videos relacionados
WWDC25
- Adopción de la concurrencia en Swift
- Codificación conjunta: Mejora una app con la concurrencia en Swift
- Conoce la contenedorización
- Explora la interoperabilidad de Swift y Java
- Mejora el uso y el rendimiento de la memoria con Swift
- Mezcle de forma segura C, C++ y Swift
WWDC24
-
Buscar este video…
-
-
9:44 - Subprocess: Call `run` with string
import Subprocess let result = try await run( .name("pwd") ) -
10:04 - Subprocess: Call `run` with file path
import Subprocess let swiftPath = FilePath("/usr/bin/swift") let result = try await run( .path(swiftPath), arguments: ["--version"] ) -
10:05 - Subprocess: Accessing standard output
import Subprocess let swiftPath = FilePath("/usr/bin/swift") let result = try await run( .path(swiftPath), arguments: ["--version"] ) let swiftVersion = result.standardOutput -
10:51 - NotificationCenter: Dynamic types
import UIKit @MainActor class KeyboardObserver { func registerObserver(screen: UIScreen) { let center = NotificationCenter.default let token = center.addObserver( forName: UIResponder.keyboardWillShowNotification, object: screen, queue: .main ) { notification in guard let userInfo = notification.userInfo else { return } let startFrame = userInfo[UIResponder.keyboardFrameBeginUserInfoKey] as? CGRect let endFrame = userInfo[UIResponder.keyboardFrameEndUserInfoKey] as? CGRect guard let startFrame, let endFrame else { return } self.keyboardWillShow(startFrame: startFrame, endFrame: endFrame) } } func keyboardWillShow(startFrame: CGRect, endFrame: CGRect) {} } -
11:34 - NotificationCenter: Concrete types
import UIKit @MainActor class KeyboardObserver { func registerObserver(screen: UIScreen) { let center = NotificationCenter.default let token = center.addObserver( of: screen, for: .keyboardWillShow ) { keyboardState in let startFrame = keyboardState.startFrame let endFrame = keyboardState.endFrame self.keyboardWillShow(startFrame: startFrame, endFrame: endFrame) } } func keyboardWillShow(startFrame: CGRect, endFrame: CGRect) {} } -
12:01 - NotificationCenter: Conformances
extension UIResponder { public struct KeyboardWillShowMessage: NotificationCenter.MainActorMessage } extension HTTPCookieStorage { public struct CookiesChangedMessage: NotificationCenter.AsyncMessage } -
12:48 - Observation: The @Observable macro
import Observation enum Item { case none case banana case star } @Observable class Player { let name: String var score: Int = 0 var item: Item = .none init(name: String) { self.name = name } } -
12:58 - Observation: The Observations type
import Observation enum Item { case none case banana case star } @Observable class Player { let name: String var score: Int = 0 var item: Item = .none init(name: String) { self.name = name } } let player = Player(name: "Holly") let values = Observations { let score = "\(player.score) points" let item = switch player.item { case .none: "no item" case .banana: "a banana" case .star: "a star" } return "\(score) and \(item)" } -
13:56 - Observation: Transactional updates
import Observation enum Item { case none case banana case star } @Observable class Player { let name: String var score: Int = 0 var item: Item = .none init(name: String) { self.name = name } } let player = Player(name: "Holly") let values = Observations { let score = "\(player.score) points" let item = switch player.item { case .none: "no item" case .banana: "a banana" case .star: "a star" } return "\(score) and \(item)" } player.score += 2 player.item = .banana -
14:05 - Observation: AsyncSequence
import Observation enum Item { case none case banana case star } @Observable class Player { let name: String var score: Int = 0 var item: Item = .none init(name: String) { self.name = name } } let player = Player(name: "Holly") let values = Observations { let score = "\(player.score) points" let item = switch player.item { case .none: "no item" case .banana: "a banana" case .star: "a star" } return "\(score) and \(item)" } player.score += 2 player.item = .banana for await value in values { print(value) } -
14:17 - Swift Testing
import Testing import Foundation import EvolutionMetadataModel @Test func validateProposalID() async throws { let (data, _) = try await URLSession.shared.data(from: evolutionJSONMetadataURL) let jsonDecoder = JSONDecoder() let metadata = try jsonDecoder.decode(EvolutionMetadata.self, from: data) for proposal in metadata.proposals { #expect(proposal.id.starts(with: "SE")) } } -
14:54 - Swift Testing: Attachments
import Testing import Foundation import EvolutionMetadataModel @Test func validateProposalID() async throws { let (data, _) = try await URLSession.shared.data(from: evolutionJSONMetadataURL) Attachment.record(data, named: "evolution-metadata.json") let jsonDecoder = JSONDecoder() let metadata = try jsonDecoder.decode(EvolutionMetadata.self, from: data) for proposal in metadata.proposals { #expect(proposal.id.starts(with: "SE")) } } -
15:23 - Exit Tests: Preconditions
extension Proposal { public var number: Int { let components = id.split(separator: "-") precondition( components.count == 2 && components[1].allSatisfy(\.isNumber), "Invalid proposal ID format \(id); expected SE-<Number>" ) return Int(components[1])! } } -
15:34 - Exit Tests: processExitsWith argument
import Testing import EvolutionMetadataModel @Test func invalidProposalPrefix() async throws { await #expect(processExitsWith: .failure) { let proposal = Proposal(id: "SE-NNNN") _ = proposal.number } } -
31:06 - Concurrency: Async function error message
class PhotoProcessor { func extractSticker(data: Data, with id: String?) async -> Sticker? { } } @MainActor final class StickerModel { let photoProcessor = PhotoProcessor() func extractSticker(_ item: PhotosPickerItem) async throws -> Sticker? { guard let data = try await item.loadTransferable(type: Data.self) else { return nil } return await photoProcessor.extractSticker(data: data, with: item.itemIdentifier) } } -
32:06 - Concurrency: Run async functions on the caller's actor
// Run async functions on the caller's actor class PhotoProcessor { func extractSticker(data: Data, with id: String?) async -> Sticker? {} } @MainActor final class StickerModel { let photoProcessor = PhotoProcessor() func extractSticker(_ item: PhotosPickerItem) async throws -> Sticker? { guard let data = try await item.loadTransferable(type: Data.self) else { return nil } return await photoProcessor.extractSticker(data: data, with: item.itemIdentifier) } } -
32:36 - Concurrency: Conformance error
protocol Exportable { func export() } extension StickerModel: Exportable { // error: Conformance of 'StickerModel' to protocol 'Exportable' crosses into main actor-isolated code and can cause data races func export() { photoProcessor.exportAsPNG() } } -
33:04 - Concurrency: Isolated conformances
// Isolated conformances protocol Exportable { func export() } extension StickerModel: @MainActor Exportable { func export() { photoProcessor.exportAsPNG() } } -
33:20 - Concurrency: Isolated conformance use
// Isolated conformances @MainActor struct ImageExporter { var items: [any Exportable] mutating func add(_ item: StickerModel) { items.append(item) } func exportAll() { for item in items { item.export() } } } -
33:31 - Concurrency: Isolated conformance error
// Isolated conformances nonisolated struct ImageExporter { var items: [any Exportable] mutating func add(_ item: StickerModel) { items.append(item) // error: Main actor-isolated conformance of 'StickerModel' to 'Exportable' cannot be used in nonisolated context } func exportAll() { for item in items { item.export() } } } -
33:51 - Concurrency: Unsafe static variable
final class StickerLibrary { static let shared: StickerLibrary = .init() // error: Static property 'shared' is not concurrency-safe because non-'Sendable' type 'StickerLibrary' may have shared mutable state } -
34:01 - Concurrency: Protecting static variables
final class StickerLibrary { @MainActor static let shared: StickerLibrary = .init() } -
34:05 - Concurrency: Protecting classes
@MainActor final class StickerLibrary { static let shared: StickerLibrary = .init() } -
34:15 - Concurrency: A single-threaded program
@MainActor final class StickerLibrary { static let shared: StickerLibrary = .init() } @MainActor final class StickerModel { let photoProcessor: PhotoProcessor var selection: [PhotosPickerItem] } extension StickerModel: @MainActor Exportable { func export() { photoProcessor.exportAsPNG() } } -
34:22 - Concurrency: Mode to infer main actor by default
// Mode to infer main actor by default final class StickerLibrary { static let shared: StickerLibrary = .init() } final class StickerModel { let photoProcessor: PhotoProcessor var selection: [PhotosPickerItem] } extension StickerModel: Exportable { func export() { photoProcessor.exportAsPNG() } } -
35:06 - Concurrency: Explicitly offloading async work
// Explicitly offloading async work class PhotoProcessor { var cachedStickers: [String: Sticker] func extractSticker(data: Data, with id: String) async -> Sticker { if let sticker = cachedStickers[id] { return sticker } let sticker = await Self.extractSubject(from: data) cachedStickers[id] = sticker return sticker } @concurrent static func extractSubject(from data: Data) async -> Sticker {} }
-
-
- 0:00 - Introducción y agenda
Conoce las novedades de Swift 6.2. Los más destacado incluye: mejoras en el flujo de trabajo, nuevas API de biblioteca, adopción ampliada en toda la pila de software y funcionalidades de lenguaje de concurrencia mejoradas para una codificación más productiva.
- 0:48 - Actualizaciones de swiftlang
La organización swiftlang en GitHub creció mucho y abarca más de 50 proyectos, incluido el compilador Swift, el sistema de compilación Swift Build de Xcode y el sitio web Swift.org. Swift Build, ahora de código abierto, admite el proceso de compilación para los sistemas operativos de Apple y forma parte del Swift Package Manager. Swiftly, desarrollado originalmente para Linux, ahora es compatible con macOS y simplifica la administración de la cadena de herramientas Swift. La página de inicio rediseñada Swift.org también puede ayudarte a profundizar en diferentes áreas.
- 3:06 - Flujo de trabajo de desarrollo: Escribir código
La última versión de Swift mejora los flujos de trabajo de desarrollo en todas las plataformas, con mejoras específicas para los usuarios de la extensión Swift de VS Code, incluida la verificación y distribución oficial de la extensión Swift por Swift.org. También hay indexación en segundo plano para funcionalidades del editor en tiempo real, autocompletado de código mejorado, depuración simplificada con soporte automático de LLDB, un nuevo panel de proyecto y vistas previas de DocC en vivo.
- 4:40 - Flujo de trabajo de desarrollo: Desarrollo
Swift 6.2 presenta varias mejoras para aumentar tu productividad. Los tiempos de compilación para proyectos que usan API basadas en macros se mejoran significativamente, ya que eliminan la necesidad de compilar la biblioteca swift-syntax durante compilaciones limpias. Esta optimización, compatible con Swift PM y Xcode, puede reducir los tiempos de compilación en minutos. Esta versión también mejora la documentación de diagnóstico del compilador debido a las explicaciones más detalladas de advertencias y errores comunes, lo que los hace más fáciles de entender y resolver. Además, tienes un mayor control sobre las advertencias del compilador; puedes especificar qué advertencias tratar como errores, una funcionalidad impulsada por la comunidad.
- 7:36 - Flujo de trabajo de desarrollo: Depuración
La depuración también se mejoró en Swift 6.2, en especial para el código asincrónico, con una funcionalidad LLDB mejorada, nombres de tareas y visibilidad en los perfiles de instrumentos. También tiene tiempos de respuesta más rápidos debido a los módulos creados explícitamente habilitados de forma predeterminada en Xcode 26.
- 9:14 - Bibliotecas: Subproceso
Esta versión presenta el nuevo paquete Subprocess, con el que puedes iniciar y administrar subprocesos directamente desde el código Swift. El paquete te brinda control detallado sobre la ejecución del proceso, por lo que puedes especificar la ruta ejecutable. Cuando finaliza el subproceso, puedes inspeccionar el estado de salida, la salida estándar y otra información sobre la ejecución del proceso, con la versión 0.1 ahora disponible y lista para recibir comentarios.
- 10:45 - Bibliotecas: Base
A fin de mejorar el desarrollo de apps de iOS, Foundation Workgroup presentó tipos concretos para nombres de notificaciones y cargas útiles, agilizó el código, eliminó errores y mejoró la seguridad tanto para las notificaciones de la estructura como para las personalizadas. También puedes agregar tipos concretos a tus notificaciones.
- 12:31 - Bibliotecas: Observación
La Observation Library de Swift usa el patrón de observador para rastrear los cambios de estado en un gráfico de objetos. La macro Observable permite el seguimiento de la observación. Swift 6.2 presenta el tipo Observations, con el que puedes crear un AsyncSequence para transmitir cambios de estado en función de un cierre que calcula un valor a partir de propiedades observables. Las actualizaciones son transaccionales, lo que garantiza un estado consistente y se pueden iterar sobre ellas mediante un bucle for-await.
- 14:13 - Bibliotecas: Prueba
Al usar Swift Testing, una biblioteca multiplataforma, puedes escribir y organizar pruebas mediante el uso de macros. Swift 6.2 mejora esta capacidad con archivos adjuntos personalizados para un mejor diagnóstico de fallas, especialmente en entornos remotos, y pruebas de salida para validar el código que finaliza en condiciones específicas. Estas funcionalidades permiten probar código Swift portátil, más allá del código de tu app.
- 16:08 - Swift en la pila: Swift integrado
Swift 6.2 mejora Embedded Swift y te permite escribir código para dispositivos integrados, servidores y componentes críticos para la seguridad. Ahora incluye API de cadena completa, tipos any de Swift para protocolos restringidos por clases y nuevas API, como InlineArray y Span, para trabajar de manera eficiente con regiones de memoria. Apple usa Embedded Swift en algunos de los programas de nivel más bajo del iPhone, y la comunidad creó ejemplos disponibles en GitHub en el repositorio swift-embedded-examples.
- 18:00 - Swift en la pila: Seguridad
Swift 6.2 presenta el modo de seguridad de memoria estricta que requiere el reconocimiento explícito de usos inseguros de API, lo que ayuda a identificar secciones de código críticas para la seguridad. Apple está adoptando este modo en WebKit y en un subsistema de la app Mensajes, que manejan entradas no confiables.
- 19:37 - Swift en la pila: Servidor
Swift se usa ampliamente en el ecosistema de servidores, particularmente en Apple, donde potencia servicios backend que procesan millones de solicitudes por segundo. Un ejemplo notable es un servicio de alerta de contraseña, desarrollado previamente en Java, con un aumento del 40% en el rendimiento y una reducción del 50% en los requisitos de hardware después de reescribirse en Swift. Otras empresas, como Cultured Code, también se beneficiaron significativamente de la adopción de Swift. El backend de Things Cloud, reimplementado en Swift, experimentó una triple reducción en los costos computacionales y una mejora del 400% en los tiempos de respuesta. El ecosistema de paquetes de Swift, la interoperabilidad con C, Objective-C y C++, y los nuevos proyectos de código abierto, como swift-java y una biblioteca de contenedorización permiten crear backends de servidor eficientes e integrar sin problemas Swift con bases de código existentes, particularmente en Java.
- 23:23 - Swift en la pila: Plataformas
Swift 6.2 ahora admite oficialmente FreeBSD y WebAssembly (Wasm), lo que te permite crear apps cliente y servidor para navegadores y otros entornos de ejecución. El soporte de Wasm, que comenzó como un proyecto comunitario, permite compilar código Swift y ejecutarlo en el navegador, como se demuestra en una app de renderizado 3D que usa WebGPU y JavaScriptKit. La seguridad, la facilidad de uso y el rendimiento de Swift lo convierten en una opción atractiva en la pila de software.
- 26:11 - Evolución del lenguaje: Rendimiento
La nueva versión también presenta dos nuevos tipos, InlineArray y Span, para mejorar el rendimiento del código crítico. InlineArray es una matriz de tamaño fijo que almacena elementos directamente y elimina la necesidad de asignación de montón. Esto mejora el rendimiento, especialmente en rutas activas, y permite más optimizaciones, como la eliminación de la comprobación de límites. El sistema especifica el tamaño de un InlineArray como parte del tipo y puede inferirlo a partir de literales de la matriz. Span proporciona acceso rápido y directo a la memoria contigua sin comprometer la seguridad de la memoria. Permite que las funciones operen sobre el almacenamiento subyacente de varios tipos de contenedores, como Array e InlineArray, de forma segura y eficiente. Span garantiza la validez de la memoria a través de verificaciones en tiempo de compilación, lo que evita problemas de seguridad de memoria comunes inherentes a los punteros.
- 30:28 - Evolución del lenguaje: Concurrencia
La concurrencia es desafiante en la programación debido a la posibilidad de carreras de datos cuando varias tareas comparten memoria. Swift 6 presentó la seguridad de carrera de datos en el momento de la compilación, pero esto a menudo causaba errores porque el lenguaje descargaba trabajo en segundo plano implícitamente, incluso si no se necesitaba que el código se ejecutara en paralelo. Swift 6.2 soluciona este problema cambiando la filosofía predeterminada para permanecer en un subproceso hasta que se introduzca explícitamente la concurrencia. Esta capacidad, por defecto, hace que el código más natural escriba datos sin restricciones. El lenguaje ahora permite que las funciones asincrónicas que no están vinculadas a un actor continúen en el mismo actor desde el que se llamaron, lo que elimina las carreras de datos. También presenta conformidades aisladas para que los tipos de actores principales se ajusten a los protocolos y también garantiza que el compilador proteja el estado del actor principal. Ahora hay un modo opcional para inferir el actor principal de manera predeterminada y reducir las anotaciones de concurrencia en código mayoritariamente de un solo subproceso. Cuando necesitas simultaneidad para mejorar el rendimiento, como por ejemplo descargar tareas intensivas de CPU en segundo plano, Swift 6.2 proporciona herramientas para hacerlo de forma segura. El atributo concurrente garantiza que funciones específicas se ejecuten en el grupo de subprocesos simultáneos, lo que libera al actor actual para realizar tareas simultáneamente. Estos cambios funcionan juntos para hacer que la concurrencia sea más accesible y más fácil de implementar en proyectos Swift.
- 37:15 - Conclusión
Los comentarios de los usuarios dieron lugar a mejoras de concurrencia en Swift y lo hicieron más fácil de usar. Se anima a la comunidad a participar en los foros en Swift.org para continuar con el desarrollo del lenguaje y el ecosistema, compartir proyectos y mantenerse al día sobre los eventos relacionados con Swift.