<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: GoyesDev</title>
    <description>The latest articles on DEV Community by GoyesDev (@david_goyes_a488f58a17a53).</description>
    <link>https://dev.to/david_goyes_a488f58a17a53</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3646790%2F7fd821bf-6de1-467c-a6b6-0ffd90e943be.jpeg</url>
      <title>DEV Community: GoyesDev</title>
      <link>https://dev.to/david_goyes_a488f58a17a53</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/david_goyes_a488f58a17a53"/>
    <language>en</language>
    <item>
      <title>[SC] Actores globales</title>
      <dc:creator>GoyesDev</dc:creator>
      <pubDate>Mon, 13 Apr 2026 23:05:25 +0000</pubDate>
      <link>https://dev.to/david_goyes_a488f58a17a53/sc-actores-globales-384b</link>
      <guid>https://dev.to/david_goyes_a488f58a17a53/sc-actores-globales-384b</guid>
      <description>&lt;h2&gt;
  
  
  Preguntas
&lt;/h2&gt;

&lt;h3&gt;
  
  
  ¿En qué se diferencia un actor global de un actor regular?
&lt;/h3&gt;

&lt;p&gt;Un &lt;code&gt;actor&lt;/code&gt; regular serializa el acceso a los datos que tiene encapsulados. Un &lt;code&gt;actor&lt;/code&gt; global, permite definir valores, tipos de datos o métodos, fuera del scope del &lt;code&gt;actor&lt;/code&gt; para que sea ejecutados con su executor.&lt;/p&gt;

&lt;h3&gt;
  
  
  ¿A qué se parece un actor global conceptualmente, y en qué se diferencia de ese concepto?
&lt;/h3&gt;

&lt;p&gt;Un actor global se parece a un singleton. Sin embargo, la diferencia radica en el uso: realmente no se "usa" el actor, sino que se "anotan" propiedades, funciones y tipos de datos para que se ejecuten dentro del executor del actor.&lt;/p&gt;

&lt;h3&gt;
  
  
  ¿A qué elementos del código se puede aplicar un actor global?
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Valores, tipos de datos (e.g. clase), funciones.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  ¿Por qué el estado global es peligroso en programas concurrentes y cómo lo resuelven los actores globales?
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Una tarea puede estar escribiendo en el estado global, mientras que otra puede estar leyendo. Esto provoca una carrera de datos.&lt;/li&gt;
&lt;li&gt;Un &lt;code&gt;actor&lt;/code&gt; global sería como marcar esa información (valor, tipo de dato, función) con un cartel que dice "acceso solo serializado".&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  ¿Qué atributo se usa para definir un actor global personalizado y qué protocolo debe conformar?
&lt;/h3&gt;

&lt;p&gt;Un actor global personalizado se define con &lt;code&gt;@globalActor&lt;/code&gt;, debe conformar el protocolo &lt;a href="https://developer.apple.com/documentation/swift/globalactor" rel="noopener noreferrer"&gt;&lt;code&gt;GlobalActor&lt;/code&gt;&lt;/a&gt; y esto se logra definiendo la propiedad &lt;code&gt;shared&lt;/code&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  ¿Qué propiedad es obligatoria para conformar al protocolo &lt;code&gt;GlobalActor&lt;/code&gt;?
&lt;/h3&gt;

&lt;p&gt;Se debe definir &lt;a href="https://developer.apple.com/documentation/swift/globalactor/shared" rel="noopener noreferrer"&gt;&lt;code&gt;shared&lt;/code&gt;&lt;/a&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  ¿Qué problema introduce no tener un inicializador privado en un actor global?
&lt;/h3&gt;

&lt;p&gt;Podría existir otro actor con un executor diferente, cuando el objetivo del actor global es poder tener un solo executor.&lt;/p&gt;

&lt;h3&gt;
  
  
  ¿Por qué se recomienda usar &lt;code&gt;private init()&lt;/code&gt; en un actor global y qué previene?
&lt;/h3&gt;

&lt;p&gt;El objetivo es impedir que se cree otra instancia del actor global.&lt;/p&gt;

&lt;h3&gt;
  
  
  ¿Cómo se usa un actor global personalizado una vez definido?
&lt;/h3&gt;

&lt;p&gt;Supongamos que se marca con &lt;code&gt;@globalActor&lt;/code&gt; al actor llamado &lt;code&gt;ActorType&lt;/code&gt;. Luego, se puede marcar con &lt;code&gt;@ActorType&lt;/code&gt; una variable global, un método o un tipo de dato.&lt;/p&gt;

&lt;h3&gt;
  
  
  ¿En qué se parece al uso de &lt;code&gt;@MainActor&lt;/code&gt;?
&lt;/h3&gt;

&lt;p&gt;&lt;code&gt;@MainActor&lt;/code&gt; es un actor global que serializa el acceso al executor de la interfaz gráfica.&lt;/p&gt;

&lt;h3&gt;
  
  
  ¿Qué ventaja tiene aislar todo el procesamiento de imágenes bajo un mismo actor global?
&lt;/h3&gt;

&lt;p&gt;Quiero que todo lo relacionado con el procesamiento de imágenes pase de forma serial: solo quiero procesar una imagen a la vez.&lt;/p&gt;




&lt;h2&gt;
  
  
  Recitar
&lt;/h2&gt;

&lt;p&gt;Sin mirar el texto, responde:&lt;/p&gt;

&lt;h3&gt;
  
  
  ¿Qué tres tipos de elementos del código puede anotar un actor global?
&lt;/h3&gt;

&lt;h3&gt;
  
  
  ¿Qué pasa si alguien llama &lt;code&gt;ImageProcessing()&lt;/code&gt; directamente sin el inicializador privado?
&lt;/h3&gt;

&lt;h3&gt;
  
  
  ¿Por qué &lt;code&gt;@MainActor&lt;/code&gt; es considerado un actor global?
&lt;/h3&gt;




&lt;h2&gt;
  
  
  Revisión
&lt;/h2&gt;

&lt;h3&gt;
  
  
  ¿Cuál es la diferencia entre un actor regular y uno global en cuanto a su alcance?
&lt;/h3&gt;

&lt;h3&gt;
  
  
  ¿Qué garantía en tiempo de compilación ofrece un actor global?
&lt;/h3&gt;

&lt;h3&gt;
  
  
  ¿Qué requisito mínimo debe cumplir un tipo para conformar a &lt;code&gt;GlobalActor&lt;/code&gt;?
&lt;/h3&gt;

&lt;h3&gt;
  
  
  ¿Qué consecuencia tendría tener dos instancias del actor &lt;code&gt;ImageProcessing&lt;/code&gt; en ejecución?
&lt;/h3&gt;




&lt;h2&gt;
  
  
  Bibliografía
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://courses.avanderlee.com/p/swift-concurrency" rel="noopener noreferrer"&gt;Van der Lee, A. (2025). &lt;em&gt;Swift Concurrency Course&lt;/em&gt; [Curso en línea]. avanderlee.com.&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>swift</category>
      <category>ios</category>
      <category>concurrency</category>
      <category>swiftconcurrency</category>
    </item>
    <item>
      <title>[SC] Actores en Swift</title>
      <dc:creator>GoyesDev</dc:creator>
      <pubDate>Mon, 13 Apr 2026 22:20:27 +0000</pubDate>
      <link>https://dev.to/david_goyes_a488f58a17a53/sc-actores-en-swift-1ipb</link>
      <guid>https://dev.to/david_goyes_a488f58a17a53/sc-actores-en-swift-1ipb</guid>
      <description>&lt;h2&gt;
  
  
  Preguntas
&lt;/h2&gt;

&lt;h3&gt;
  
  
  ¿Qué es un &lt;code&gt;actor&lt;/code&gt; en Swift Concurrency y en qué se diferencia de una clase?
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Un &lt;code&gt;actor&lt;/code&gt; es un tipo de dato por referencia, parecido a un &lt;code&gt;class&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;actor&lt;/code&gt; no puede heredar de otros tipos de datos, a excepción de &lt;code&gt;NSObject&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;actor&lt;/code&gt; garantiza acceso serializado a los datos que encapsula.&lt;/li&gt;
&lt;li&gt;No se puede modificar directamente los datos de &lt;code&gt;actor&lt;/code&gt;, sino que se debe hacer a través de métodos, que deben ser invocados con &lt;code&gt;await&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Se puede leer los datos del &lt;code&gt;actor&lt;/code&gt; de forma asíncrona, con &lt;code&gt;await&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  ¿Qué garantía fundamental ofrece el aislamiento de actores (actor isolation)?
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Solo una tarea puede acceder a los datos de forma simultánea.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  ¿Por qué no puedes mutar directamente una propiedad de un actor desde fuera de él, aunque no sea private?
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;La mutación debe pasar por el executor del actor para que este la serialice.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  ¿Qué es un executor y cuál es su función dentro de un actor?
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Un executor es una especie de cola serial que gestiona el acceso al dominio de aislamiento del actor.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  ¿En qué se diferencia el executor de un actor de una &lt;code&gt;DispatchQueue&lt;/code&gt; serial?
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;DispatchQueue&lt;/code&gt; serial bloquea el hilo, mientras que el &lt;code&gt;actor&lt;/code&gt; es reentrante, dado que su executor puede ejecutar otras tareas cuando se encuentra con &lt;code&gt;await&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  ¿Por qué siempre debes usar &lt;code&gt;await&lt;/code&gt; para acceder a propiedades o métodos de un actor?
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Puede ser que otra tarea esté modificando o leyendo una propiedad del actor, así que hay que esperar hasta poder acceder a ella.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  ¿Cuál es la diferencia entre leer y mutar una propiedad de un actor desde fuera?
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Se puede leer con &lt;code&gt;await&lt;/code&gt; pero no se puede mutar desde fuera.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  ¿Por qué los actores no soportan herencia y qué implica eso en la práctica?
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;La responsabilidad del &lt;code&gt;actor&lt;/code&gt; es aislar el acceso a los datos, así que no hay que usar &lt;code&gt;open&lt;/code&gt;, &lt;code&gt;final&lt;/code&gt; u &lt;code&gt;override&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;En la práctica implica que hay que usar composición sobre herencia.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  ¿Cuál es la única excepción a la regla de no herencia en actores, y para qué sirve?
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Un actor puede heredar de &lt;code&gt;NSObject&lt;/code&gt; y sirve para interoperabilidad con ObjC.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  ¿Qué analogía usa el artículo para describir el acceso a un actor y por qué es adecuada?
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Un &lt;code&gt;actor&lt;/code&gt; es como un semáforo: Si de entrada está en verde, puedo pasar. Si está en rojo, debo esperar. - Esto es esencialmente lo que pasa con &lt;code&gt;await&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Recitar
&lt;/h2&gt;

&lt;p&gt;Sin mirar el artículo, responde con tus propias palabras:&lt;/p&gt;

&lt;h3&gt;
  
  
  ¿Cómo serializa el acceso un actor internamente?
&lt;/h3&gt;

&lt;h3&gt;
  
  
  ¿Qué error produce el compilador si intentas mutar balance directamente?
&lt;/h3&gt;

&lt;h3&gt;
  
  
  ¿Qué hace un actor cuando uno de sus métodos llega a un &lt;code&gt;await&lt;/code&gt;?
&lt;/h3&gt;




&lt;h2&gt;
  
  
  Revisión
&lt;/h2&gt;

&lt;h3&gt;
  
  
  ¿En qué se parece y en qué se diferencia un actor de una clase?
&lt;/h3&gt;

&lt;h3&gt;
  
  
  ¿Qué problema resuelve el actor que no resolvía NSLock automáticamente?
&lt;/h3&gt;

&lt;h3&gt;
  
  
  ¿Por qué el executor de un actor sí puede ser reentrante y una &lt;code&gt;DispatchQueue&lt;/code&gt; serial no?
&lt;/h3&gt;

&lt;h3&gt;
  
  
  Si un &lt;code&gt;actor&lt;/code&gt; es un tipo referencia, ¿cómo garantiza igualmente la seguridad de datos?
&lt;/h3&gt;




&lt;h2&gt;
  
  
  Bibliografía
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://courses.avanderlee.com/p/swift-concurrency" rel="noopener noreferrer"&gt;Van der Lee, A. (2025). &lt;em&gt;Swift Concurrency Course&lt;/em&gt; [Curso en línea]. avanderlee.com.&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>swift</category>
      <category>ios</category>
      <category>concurrency</category>
      <category>swiftconcurrency</category>
    </item>
    <item>
      <title>[SC] Combinando Sendable con Locks personalizados</title>
      <dc:creator>GoyesDev</dc:creator>
      <pubDate>Mon, 13 Apr 2026 15:22:47 +0000</pubDate>
      <link>https://dev.to/david_goyes_a488f58a17a53/sc-combinando-sendable-con-locks-personalizados-1m06</link>
      <guid>https://dev.to/david_goyes_a488f58a17a53/sc-combinando-sendable-con-locks-personalizados-1m06</guid>
      <description>&lt;h2&gt;
  
  
  Q — Questions (Preguntas)
&lt;/h2&gt;

&lt;p&gt;Convierte los encabezados en preguntas de estudio:&lt;/p&gt;

&lt;h3&gt;
  
  
  ¿Qué es un mecanismo de bloqueo (&lt;code&gt;lock&lt;/code&gt;) y para qué se usa en concurrencia?
&lt;/h3&gt;

&lt;p&gt;Un "lock" es un mecanismo de sincronización de hilos que sirve para proteger el acceso y modificación de un dato. Se usa en concurrencia para que no haya carreras de datos.&lt;/p&gt;

&lt;h3&gt;
  
  
  ¿Cómo protege &lt;code&gt;NSLock&lt;/code&gt; el acceso a datos mutables compartidos en la clase &lt;code&gt;BankAccount&lt;/code&gt;?
&lt;/h3&gt;

&lt;p&gt;En &lt;code&gt;BankAccount&lt;/code&gt; hay una propiedad, &lt;code&gt;balance&lt;/code&gt; que se debe proteger con un &lt;code&gt;NSLock&lt;/code&gt;: Cada vez que se accede al método se bloquea (&lt;code&gt;.lock()&lt;/code&gt;) y justo antes de salir de cada método se libera (&lt;code&gt;.unlock()&lt;/code&gt;).&lt;/p&gt;

&lt;h3&gt;
  
  
  ¿Por qué el ejemplo de &lt;code&gt;BankAccount&lt;/code&gt; es útil para entender los actores más adelante?
&lt;/h3&gt;

&lt;p&gt;En el contexto de concurrencia de Swift, el actor permite invocar sus métodos con &lt;code&gt;await&lt;/code&gt; con lo que consigue serializar los accesos a los datos. Si se va a escribir código nuevo, lo ideal es usar un &lt;code&gt;actor&lt;/code&gt;. Sin embargo, en código pre-existente hay que evaluar si basta con usar &lt;code&gt;@unchecked Sendable&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;El ejemplo inicial de &lt;code&gt;BankAccount&lt;/code&gt; ilustra el acceso a &lt;code&gt;balance&lt;/code&gt; de forma serializada con ayuda del &lt;code&gt;NSLock&lt;/code&gt;. Usar el &lt;code&gt;lock&lt;/code&gt; es una convención. Por otro lado, la implementación con &lt;code&gt;actor&lt;/code&gt; también serializa el acceso a los datos (en este caso, &lt;code&gt;balance&lt;/code&gt;) con la diferencia de que aquí no hay ninguna convención sino que el lenguaje garantiza este comportamiento.&lt;/p&gt;

&lt;h3&gt;
  
  
  ¿En qué situaciones conviene usar &lt;code&gt;@unchecked Sendable&lt;/code&gt; en lugar de refactorizar a un actor?
&lt;/h3&gt;

&lt;p&gt;Si el código es bastante estable, la sincronización del acceso a datos es segura, y si la clase en cuestión tiene muchos clientes y su refactorización puede ser compleja, se puede usar &lt;code&gt;@unchecked Sendable&lt;/code&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  ¿Qué implica técnicamente migrar una clase con locks a un actor en Swift?
&lt;/h3&gt;

&lt;p&gt;Acceder a todos los métodos requiere usar &lt;code&gt;await&lt;/code&gt;, lo que implica que el consumo es asíncrono.&lt;/p&gt;

&lt;h3&gt;
  
  
  ¿Cuáles son las desventajas de migrar de inmediato a un actor en una base de código existente?
&lt;/h3&gt;

&lt;p&gt;Se tendría que modificar a todos los clientes para invocar los métodos del actor con &lt;code&gt;await&lt;/code&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  ¿Cuándo se recomienda usar &lt;code&gt;Mutex&lt;/code&gt; en lugar de &lt;code&gt;NSLock&lt;/code&gt; o actores?
&lt;/h3&gt;

&lt;p&gt;Si se quiere sincronizar los hilos y también tener acceso a la clase en cuestión de forma síncrona, entonces se usa &lt;code&gt;Mutex&lt;/code&gt;.&lt;/p&gt;




&lt;h3&gt;
  
  
  R — Recite (Recitar)
&lt;/h3&gt;

&lt;p&gt;Sin mirar el texto, responde con tus propias palabras:&lt;/p&gt;

&lt;h3&gt;
  
  
  ¿Cómo funciona el flujo de bloqueo/desbloqueo en &lt;code&gt;BankAccount&lt;/code&gt;?
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight swift"&gt;&lt;code&gt;&lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="kt"&gt;BankAccount&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kd"&gt;@unchecked&lt;/span&gt; &lt;span class="kt"&gt;Sendable&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="nv"&gt;balance&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;Int&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;
  &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;lock&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kt"&gt;NSLock&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

  &lt;span class="kd"&gt;func&lt;/span&gt; &lt;span class="nf"&gt;deposit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;amount&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;Int&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;lock&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;lock&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="n"&gt;balance&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="n"&gt;amount&lt;/span&gt;
    &lt;span class="n"&gt;lock&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;unlock&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="kd"&gt;func&lt;/span&gt; &lt;span class="nf"&gt;withdraw&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;amount&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;Int&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;lock&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;lock&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;balance&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;=&lt;/span&gt; &lt;span class="n"&gt;amount&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="n"&gt;balance&lt;/span&gt; &lt;span class="o"&gt;-=&lt;/span&gt; &lt;span class="n"&gt;amount&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="n"&gt;lock&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;unlock&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="kd"&gt;func&lt;/span&gt; &lt;span class="nf"&gt;getBalance&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="kt"&gt;Int&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;lock&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;lock&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;currentBalance&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;balance&lt;/span&gt;
    &lt;span class="n"&gt;lock&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;unlock&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;currentBalance&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight swift"&gt;&lt;code&gt;&lt;span class="kd"&gt;actor&lt;/span&gt; &lt;span class="kt"&gt;BankAccount&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="nv"&gt;balance&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;Int&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;

  &lt;span class="kd"&gt;func&lt;/span&gt; &lt;span class="nf"&gt;deposit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;amount&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;Int&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;balance&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="n"&gt;amount&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="kd"&gt;func&lt;/span&gt; &lt;span class="nf"&gt;withdraw&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;amount&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;Int&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;balance&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;=&lt;/span&gt; &lt;span class="n"&gt;amount&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="n"&gt;balance&lt;/span&gt; &lt;span class="o"&gt;-=&lt;/span&gt; &lt;span class="n"&gt;amount&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="kd"&gt;func&lt;/span&gt; &lt;span class="nf"&gt;getBalance&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="kt"&gt;Int&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;balance&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  ¿Qué garantiza &lt;code&gt;@unchecked Sendable&lt;/code&gt; y qué responsabilidad transfiere al desarrollador?
&lt;/h3&gt;

&lt;h3&gt;
  
  
  ¿Qué cambia en el código que consume &lt;code&gt;BankAccount&lt;/code&gt; cuando se migra a actor?
&lt;/h3&gt;




&lt;h2&gt;
  
  
  R — Review (Revisión)
&lt;/h2&gt;

&lt;p&gt;Preguntas de repaso para consolidar:&lt;/p&gt;

&lt;h3&gt;
  
  
  ¿Cuál es la diferencia entre una clase con &lt;code&gt;NSLock&lt;/code&gt; y un actor en términos de acceso concurrente?
&lt;/h3&gt;

&lt;h3&gt;
  
  
  ¿Por qué &lt;code&gt;@unchecked Sendable&lt;/code&gt; es una solución temporal y no definitiva?
&lt;/h3&gt;

&lt;h3&gt;
  
  
  ¿Qué acción concreta recomienda el autor para no olvidar la deuda técnica al usar &lt;code&gt;@unchecked Sendable&lt;/code&gt;?
&lt;/h3&gt;

&lt;h3&gt;
  
  
  ¿Qué factores debes considerar antes de decidir si migrar a un actor de inmediato?
&lt;/h3&gt;




&lt;h2&gt;
  
  
  Bibliografía
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://courses.avanderlee.com/p/swift-concurrency" rel="noopener noreferrer"&gt;Van der Lee, A. (2025). &lt;em&gt;Swift Concurrency Course&lt;/em&gt; [Curso en línea]. avanderlee.com.&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>swift</category>
      <category>ios</category>
      <category>concurrency</category>
      <category>swiftconcurrency</category>
    </item>
    <item>
      <title>[SC] Valores globales seguros para concurrencia</title>
      <dc:creator>GoyesDev</dc:creator>
      <pubDate>Sat, 11 Apr 2026 17:16:39 +0000</pubDate>
      <link>https://dev.to/david_goyes_a488f58a17a53/sc-valores-globales-seguros-para-concurrencia-21g4</link>
      <guid>https://dev.to/david_goyes_a488f58a17a53/sc-valores-globales-seguros-para-concurrencia-21g4</guid>
      <description>&lt;h2&gt;
  
  
  Preguntas
&lt;/h2&gt;

&lt;h3&gt;
  
  
  ¿Qué es una variable global y por qué su uso implica riesgos en contextos de concurrencia?
&lt;/h3&gt;

&lt;p&gt;Una variable global es un valor que puede ser accedido y modificado desde cualquier parte del sistema, esto incluye cualquier contexto asíncrono.&lt;/p&gt;

&lt;h3&gt;
  
  
  ¿Qué error genera el compilador de Swift 6 cuando una variable global es mutable y no está aislada?
&lt;/h3&gt;

&lt;p&gt;Tomemos como ejemplo la clase no aislada &lt;code&gt;ImageCache&lt;/code&gt;, que tiene una variable global mutable no aislada llamada &lt;code&gt;shared&lt;/code&gt;. En este caso, el compilador saca un error indicando que no es seguro acceder a un estado global mutable desde un entorno concurrente.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight swift"&gt;&lt;code&gt;&lt;span class="kd"&gt;nonisolated&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="kt"&gt;ImageCache&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="nv"&gt;shared&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kt"&gt;ImageCache&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
  &lt;span class="c1"&gt;// ❌ Static property 'shared' is not concurrency-safe because it is nonisolated global shared mutable state&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  ¿Cuáles son las tres estrategias principales para hacer una variable global segura para la concurrencia?
&lt;/h3&gt;

&lt;h4&gt;
  
  
  1. Aislar el acceso a la clase con un actor global como &lt;code&gt;@MainActor&lt;/code&gt;.
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Ventaja:&lt;/strong&gt; &lt;code&gt;@MainActor&lt;/code&gt; garantiza que el acceso a &lt;code&gt;ImageCache&lt;/code&gt; es serializado.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Desventaja:&lt;/strong&gt; Complica el acceso desde otros dominios de aislamiento o contextos no-concurrentes&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Por ejemplo:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight swift"&gt;&lt;code&gt;&lt;span class="kd"&gt;@MainActor&lt;/span&gt;
&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="kt"&gt;ImageCache&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="nv"&gt;shared&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kt"&gt;ImageCache&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
  &lt;span class="c1"&gt;// ✅ No hay error&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight swift"&gt;&lt;code&gt;&lt;span class="kd"&gt;nonisolated&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="kt"&gt;NonConcurrentContext&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;func&lt;/span&gt; &lt;span class="nf"&gt;execute&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;sut&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kt"&gt;ImageCache&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;shared&lt;/span&gt;
    &lt;span class="c1"&gt;// ❌ Main actor-isolated static property 'shared' can not be referenced from a nonisolated context&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight swift"&gt;&lt;code&gt;&lt;span class="kd"&gt;fileprivate&lt;/span&gt; &lt;span class="kd"&gt;actor&lt;/span&gt; &lt;span class="kt"&gt;ActorContext&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;func&lt;/span&gt; &lt;span class="nf"&gt;execute&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;sut&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kt"&gt;ImageCache&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;shared&lt;/span&gt;
    &lt;span class="c1"&gt;// ❌ Main actor-isolated static property 'shared' can not be referenced on a nonisolated actor instance&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  2. Conformar &lt;code&gt;Sendable&lt;/code&gt;
&lt;/h4&gt;

&lt;p&gt;Esto es:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Hacer que la clase sea inmutable.&lt;/li&gt;
&lt;li&gt;Marcar con &lt;code&gt;final&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Mutar las variables por medio de &lt;code&gt;locks&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Recordar que el protocolo &lt;code&gt;Sendable&lt;/code&gt; indica que el API del tipo en cuestión es thread-safe y se puede usar sin problema entre dominios de aislamiento.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight swift"&gt;&lt;code&gt;&lt;span class="c1"&gt;// ✅ final&lt;/span&gt;
&lt;span class="kd"&gt;nonisolated&lt;/span&gt; &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="kt"&gt;ImageCache&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;Sendable&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;

  &lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;shared&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kt"&gt;ImageCache&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
  &lt;span class="c1"&gt;// ✅ let, no var&lt;/span&gt;

  &lt;span class="kd"&gt;func&lt;/span&gt; &lt;span class="nf"&gt;clearCache&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// ...&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight swift"&gt;&lt;code&gt;&lt;span class="kd"&gt;fileprivate&lt;/span&gt; &lt;span class="kd"&gt;actor&lt;/span&gt; &lt;span class="kt"&gt;ActorContext&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;func&lt;/span&gt; &lt;span class="nf"&gt;execute&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;sut&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kt"&gt;ImageCache&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;shared&lt;/span&gt;
    &lt;span class="c1"&gt;// ✅ No hay error&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight swift"&gt;&lt;code&gt;&lt;span class="kd"&gt;fileprivate&lt;/span&gt; &lt;span class="kd"&gt;nonisolated&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="kt"&gt;NonConcurrentContext&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;func&lt;/span&gt; &lt;span class="nf"&gt;execute&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;sut&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kt"&gt;ImageCache&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;shared&lt;/span&gt;
    &lt;span class="c1"&gt;// ✅ No hay error&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  3. Marcar el tipo como &lt;code&gt;Sendable&lt;/code&gt; y la propiedad mutable como nonisolated(unsafe)
&lt;/h4&gt;

&lt;p&gt;Si el API no se puede modificar con facilidad (para conformar &lt;code&gt;Sendable&lt;/code&gt;) y tiene partes mutables, se puede marcar a estas últimas como &lt;code&gt;nonisolated(unsafe)&lt;/code&gt;, que es el equivalente a usar &lt;code&gt;@unchecked Sendable&lt;/code&gt;. Básicamente se le está diciendo al compilador que el desarrollador se hace responsable de sincronizar el acceso a ese valor global, sin introducir data-races.&lt;/p&gt;

&lt;p&gt;Lo ideal es solo modificar el valor global en el arranque de la aplicación y luego leerlo desde otros contextos de concurrencia, para lo cual se puede usar el modificador &lt;code&gt;private(set)&lt;/code&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  ¿Cuándo y por qué se usaría &lt;code&gt;nonisolated(unsafe)&lt;/code&gt; en lugar de las otras soluciones?
&lt;/h3&gt;

&lt;p&gt;Cuando el código tiene un patrón de inicialización tardía que no puedo reescribir fácilmente.&lt;/p&gt;

&lt;h3&gt;
  
  
  ¿Qué condiciones debe cumplir una clase para conformar al protocolo &lt;code&gt;Sendable&lt;/code&gt;?
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;marcada como &lt;code&gt;final&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;miembros inmutables.&lt;/li&gt;
&lt;li&gt;acceso a miembros mutables por medio de &lt;code&gt;locks&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Lectura
&lt;/h2&gt;

&lt;h3&gt;
  
  
  ¿Por qué aislar una clase con &lt;code&gt;@MainActor&lt;/code&gt; puede ser problemático en algunos casos?
&lt;/h3&gt;

&lt;p&gt;El acceso desde otros dominios de aislamiento o &lt;code&gt;nonisolated&lt;/code&gt; tendrá que ser usando &lt;code&gt;await&lt;/code&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  ¿Qué papel juega &lt;code&gt;private(set)&lt;/code&gt; cuando se usa junto con &lt;code&gt;nonisolated(unsafe)&lt;/code&gt;?
&lt;/h3&gt;

&lt;p&gt;El objetivo es que solo la clase que define el singleton pueda modificar la variable estática y que ningún cliente lo haga.&lt;/p&gt;

&lt;h3&gt;
  
  
  ¿En qué se parece &lt;code&gt;nonisolated(unsafe)&lt;/code&gt; al uso de &lt;code&gt;@unchecked Sendable&lt;/code&gt;?
&lt;/h3&gt;

&lt;p&gt;Se le dice al compilador que el desarrollador se compromete a garantizar que no hay carreras de datos.&lt;/p&gt;




&lt;h2&gt;
  
  
  Revisión
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Sin volver atrás ¿puedes explicar con tus propias palabras qué hace que una variable global sea peligrosa en Swift 6?
&lt;/h3&gt;

&lt;h3&gt;
  
  
  ¿Puedes describir de memoria los pasos para convertir &lt;code&gt;ImageCache&lt;/code&gt; en una clase segura para la concurrencia?
&lt;/h3&gt;

&lt;h3&gt;
  
  
  ¿Cuál de las tres soluciones presentadas consideras más adecuada para un proyecto en producción y por qué?
&lt;/h3&gt;

&lt;h3&gt;
  
  
  ¿Qué riesgos asumes al marcar una variable como &lt;code&gt;nonisolated(unsafe)&lt;/code&gt;, y cómo podrías mitigarlos?
&lt;/h3&gt;




&lt;h2&gt;
  
  
  Bibliografía
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://courses.avanderlee.com/p/swift-concurrency" rel="noopener noreferrer"&gt;Van der Lee, A. (2025). &lt;em&gt;Swift Concurrency Course&lt;/em&gt; [Curso en línea]. avanderlee.com.&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>swift</category>
      <category>ios</category>
      <category>concurrency</category>
      <category>swiftconcurrency</category>
    </item>
    <item>
      <title>[SC] Aislamiento basado en regiones y la palabra clave "sending"</title>
      <dc:creator>GoyesDev</dc:creator>
      <pubDate>Sat, 11 Apr 2026 00:34:13 +0000</pubDate>
      <link>https://dev.to/david_goyes_a488f58a17a53/sc-aislamiento-basado-en-regiones-y-la-palabra-clave-sending-2apa</link>
      <guid>https://dev.to/david_goyes_a488f58a17a53/sc-aislamiento-basado-en-regiones-y-la-palabra-clave-sending-2apa</guid>
      <description>&lt;h2&gt;
  
  
  Preguntas
&lt;/h2&gt;

&lt;h3&gt;
  
  
  ¿Qué es el aislamiento basado en regiones (region-based isolation) y por qué existe?
&lt;/h3&gt;

&lt;p&gt;El sistema original de &lt;code&gt;Sendable&lt;/code&gt; era demasiado estricto y bloqueaba patrones de código seguros que usaban código no-&lt;code&gt;Sendable&lt;/code&gt;. Por esto se creó el &lt;em&gt;"aislamiento basado en regiones"&lt;/em&gt;, el cual es un mecanismo del compilador que verifica si un tipo no-&lt;code&gt;Sendable&lt;/code&gt; se usa únicamente dentro de un scope.&lt;/p&gt;

&lt;h3&gt;
  
  
  ¿En qué situaciones el compilador ignora errores de tipos no-&lt;code&gt;Sendable&lt;/code&gt;?
&lt;/h3&gt;

&lt;p&gt;Si se crea un valor localmente dentro de una función, no se muta y no se accede a él después de transferirlo a otro dominio de aislamiento, entonces el compilador puede garantizar que no hay acceso simultáneo.&lt;/p&gt;

&lt;h3&gt;
  
  
  ¿Qué son los diagnósticos sensibles al flujo de control (control flow-sensitive diagnostics)?
&lt;/h3&gt;

&lt;p&gt;El &lt;em&gt;"diagnóstico sensible al flujo de control"&lt;/em&gt; es un análisis de código estático que hace el compilador para determinar que un tipo no-&lt;code&gt;Sendable&lt;/code&gt; puede transferirse de forma segura a otro dominio de aislamiento.&lt;/p&gt;

&lt;p&gt;El compilador revisa si el valor se usa o no después del punto de transferencia.&lt;/p&gt;

&lt;h3&gt;
  
  
  ¿Cuándo deja de compilar el código aunque se use aislamiento basado en regiones?
&lt;/h3&gt;

&lt;p&gt;Cuando se usa el valor después de haberlo transferido a otro dominio de aislamiento.&lt;/p&gt;

&lt;h3&gt;
  
  
  ¿Qué problema resuelve la palabra clave &lt;code&gt;sending&lt;/code&gt;?
&lt;/h3&gt;

&lt;p&gt;&lt;code&gt;sending&lt;/code&gt; declara explícitamente una transferencia de propiedad, por lo que compilador mueve las verificaciones hacia el interior del método receptor.&lt;/p&gt;

&lt;p&gt;De esta forma se puede silenciar un posible error cuando el desarrollador sabe que no hay riesgo de data-race.&lt;/p&gt;

&lt;h3&gt;
  
  
  ¿Cuál es la diferencia entre usar &lt;code&gt;sending&lt;/code&gt; en parámetros y en valores de retorno?
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;sending&lt;/code&gt; como parámetro garantiza que el invocador del método no puede volver a utilizar la propiedad. Además, solo se puede transferir a un solo dominio de aislamiento.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;sending&lt;/code&gt; como retorno indica que la función no conserva referencia al valor y lo transfiere hacia fuera.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  ¿Por qué un tipo no-&lt;code&gt;Sendable&lt;/code&gt; dentro de un método local no genera error al pasarse a una &lt;code&gt;Task&lt;/code&gt;?
&lt;/h3&gt;

&lt;p&gt;El compilador es capaz de identificar que el valor nació en esa función, nadie más tiene referencia a él y, si no se accede después del &lt;code&gt;Task&lt;/code&gt;, no puede haber un acceso simultáneo.&lt;/p&gt;

&lt;h3&gt;
  
  
  ¿Qué ocurre si accedes a un valor después de haberlo transferido con &lt;code&gt;sending&lt;/code&gt;?
&lt;/h3&gt;

&lt;p&gt;El compilador indica que se está usando el valor transferido y los accesos posteriores podrían generar una condición de carrera.&lt;/p&gt;




&lt;h2&gt;
  
  
  Ejemplos con código
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;Article&lt;/code&gt; es una clase no-&lt;code&gt;Sendable&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight swift"&gt;&lt;code&gt;&lt;span class="kd"&gt;nonisolated&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="kt"&gt;Article&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="nv"&gt;title&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;"String"&lt;/span&gt;

  &lt;span class="nf"&gt;init&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;title&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;"String) {"&lt;/span&gt;
    &lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;title&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;title&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Puedo recibir un &lt;code&gt;Article&lt;/code&gt; y pasárselo de forma segura &lt;strong&gt;UN SOLO&lt;/strong&gt; dominio de aislamiento. Para ello, puedo modificar un parámetro con &lt;code&gt;sending&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight swift"&gt;&lt;code&gt;&lt;span class="kd"&gt;nonisolated&lt;/span&gt; &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="kt"&gt;ArticleConsumer&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;func&lt;/span&gt; &lt;span class="nf"&gt;execute&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;article&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;sending&lt;/span&gt; &lt;span class="kt"&gt;Article&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kt"&gt;Task&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// ❌ Sending value of non-Sendable type '@concurrent () async -&amp;gt; ()' risks causing data races&lt;/span&gt;
      &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;article&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;title&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;article&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;title&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;En este caso, la clase &lt;code&gt;ArticleConsumer&lt;/code&gt; vive en el dominio &lt;code&gt;nonisolated&lt;/code&gt;. En el método &lt;code&gt;execute(article:)&lt;/code&gt;, se transfiere &lt;code&gt;article&lt;/code&gt; desde &lt;code&gt;nonisolated&lt;/code&gt; hasta la región sin estructura del &lt;code&gt;Task&lt;/code&gt;.  En este punto, el método que transfiere (i.e. &lt;code&gt;execute(article:)&lt;/code&gt; ya no puede volver a usarlo (i.e. llamar &lt;code&gt;print(article.title)&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Con lo anterior quiero decir que al usar &lt;code&gt;sending&lt;/code&gt; solo se puede transferir el dato a través de &lt;strong&gt;UN SOLO&lt;/strong&gt; dominio de aislamiento.&lt;/p&gt;

&lt;p&gt;Sucede lo mismo en el siguiente escenario, donde el dominio de aislamiento al que se transfiere &lt;code&gt;article&lt;/code&gt; es un &lt;code&gt;actor&lt;/code&gt; en lugar de un &lt;code&gt;Task&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight swift"&gt;&lt;code&gt;&lt;span class="kd"&gt;actor&lt;/span&gt; &lt;span class="kt"&gt;ArticleStore&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;func&lt;/span&gt; &lt;span class="nf"&gt;save&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;_&lt;/span&gt; &lt;span class="nv"&gt;article&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;Article&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;article&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;title&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight swift"&gt;&lt;code&gt;&lt;span class="kd"&gt;nonisolated&lt;/span&gt; &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="kt"&gt;ArticleConsumerWithActor&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;func&lt;/span&gt; &lt;span class="nf"&gt;execute&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;article&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;sending&lt;/span&gt; &lt;span class="kt"&gt;Article&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;store&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kt"&gt;ArticleStore&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;store&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;save&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;article&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="c1"&gt;// ❌ Sending 'article' risks causing data races&lt;/span&gt;
    &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;article&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;title&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;No obstante, todo este análisis funciona porque tanto &lt;code&gt;ArticleConsumerWithActor&lt;/code&gt; como &lt;code&gt;ArticleConsumer&lt;/code&gt; están marcados con &lt;code&gt;nonisolated&lt;/code&gt;. Si no tuvieran ese modificador y tuviéramos las propiedades de configuración del proyecto &lt;code&gt;SWIFT_DEFAULT_ACTOR_ISOLATION = MainActor&lt;/code&gt; y &lt;code&gt;SWIFT_VERSION = 6.0&lt;/code&gt;, entonces tanto &lt;code&gt;ArticleConsumerWithActor&lt;/code&gt; como &lt;code&gt;ArticleConsumer&lt;/code&gt; vivirían en &lt;code&gt;@MainActor&lt;/code&gt; implícitamente.&lt;/p&gt;

&lt;p&gt;Luego, cuando se crea un &lt;code&gt;Task&lt;/code&gt; dentro del contexto aislado &lt;code&gt;MainActor&lt;/code&gt;, la &lt;code&gt;Task&lt;/code&gt; hereda el mismo aislamiento &lt;code&gt;MainActor&lt;/code&gt;. De esta forma, tanto la &lt;code&gt;Task&lt;/code&gt; como el cuerpo del método &lt;code&gt;ArticleConsumer.execute(article:)&lt;/code&gt; vivirán en &lt;code&gt;@MainActor&lt;/code&gt;. Más tarde, cuando el compilador hace el análisis de código estático para el dianóstico de regiones encontrará que no se está cruzando ninguna región y usar &lt;code&gt;article&lt;/code&gt; después del &lt;code&gt;Task&lt;/code&gt; es legal.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight swift"&gt;&lt;code&gt;&lt;span class="c1"&gt;// ⚠️ hereda @MainActor implícitamente&lt;/span&gt;
&lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="kt"&gt;ArticleConsumer&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;func&lt;/span&gt; &lt;span class="nf"&gt;execute&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;article&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;sending&lt;/span&gt; &lt;span class="kt"&gt;Article&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kt"&gt;Task&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="c1"&gt;// ✅ No saca ningún error&lt;/span&gt;
      &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;article&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;title&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;article&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;title&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Recitación
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Explica con tus propias palabras cómo el compilador determina si hay riesgo de data race.
&lt;/h3&gt;

&lt;p&gt;El compilador sigue el código y marca el punto donde un valor se transfiere de un dominio a otro. Si no se vuelve a transferir, no hay problema. Si, en cambio, se transfiere, entonces hay dos zonas con acceso potencial simultáneo y saca un error.&lt;/p&gt;

&lt;h3&gt;
  
  
  ¿Por qué agregar un &lt;code&gt;print&lt;/code&gt; después de la transferencia rompe la compilación?
&lt;/h3&gt;

&lt;p&gt;La &lt;code&gt;Task&lt;/code&gt; podría estar ejecutándose en paralelo al tiempo que el &lt;code&gt;print&lt;/code&gt;. Esas dos zonas pueden acceder simultáneamente al mismo valor, y esto es lo que quiere prevenir Swift.&lt;/p&gt;




&lt;h2&gt;
  
  
  Revisión
&lt;/h2&gt;

&lt;h3&gt;
  
  
  ¿En qué casos concretos usarías &lt;code&gt;sending&lt;/code&gt; en lugar de conformar un tipo a &lt;code&gt;Sendable&lt;/code&gt;?
&lt;/h3&gt;

&lt;p&gt;La clase en cuestión no puede ser &lt;code&gt;Sendable&lt;/code&gt;. Pueden tener estado mutable pero en cierto contexto pasa de forma controlada y sin acceso concurrente.&lt;/p&gt;

&lt;h3&gt;
  
  
  ¿Cómo reduce el aislamiento basado en regiones la necesidad de usar &lt;code&gt;Sendable&lt;/code&gt;?
&lt;/h3&gt;

&lt;p&gt;El compilador analiza cada caso específicamente. Si en un scope es seguro usar un valor, no es necesario que conforme &lt;code&gt;Sendable&lt;/code&gt;.&lt;/p&gt;




&lt;h2&gt;
  
  
  Bibliografía
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://courses.avanderlee.com/p/swift-concurrency" rel="noopener noreferrer"&gt;Van der Lee, A. (2025). &lt;em&gt;Swift Concurrency Course&lt;/em&gt; [Curso en línea]. avanderlee.com.&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>swift</category>
      <category>ios</category>
      <category>concurrency</category>
      <category>swiftconcurrency</category>
    </item>
    <item>
      <title>[SC] @unchecked Sendable</title>
      <dc:creator>GoyesDev</dc:creator>
      <pubDate>Fri, 10 Apr 2026 16:52:05 +0000</pubDate>
      <link>https://dev.to/david_goyes_a488f58a17a53/sc-unchecked-sendable-1id7</link>
      <guid>https://dev.to/david_goyes_a488f58a17a53/sc-unchecked-sendable-1id7</guid>
      <description>&lt;h2&gt;
  
  
  Preguntas
&lt;/h2&gt;

&lt;h3&gt;
  
  
  ¿Qué significa exactamente &lt;code&gt;@unchecked Sendable&lt;/code&gt; y en qué se diferencia de &lt;code&gt;Sendable&lt;/code&gt; normal?
&lt;/h3&gt;

&lt;p&gt;&lt;code&gt;@unchecked Sendable&lt;/code&gt; significa que un tipo de dato específico conforma el contrato &lt;code&gt;Sendable&lt;/code&gt; pero, a pesar de que el compilador podría no ser capaz de garantizar las condiciones del contrato, el desarrollador remueve esa validación y él se compromete a sincronizar el acceso a datos.&lt;/p&gt;

&lt;h3&gt;
  
  
  ¿En qué situaciones es apropiado usar &lt;code&gt;@unchecked Sendable&lt;/code&gt;?
&lt;/h3&gt;

&lt;p&gt;Se puede usar &lt;code&gt;@unchecked Sendable&lt;/code&gt; si el código ha demostrado ser seguro en un ambiente concurrente y se usa como solución temporal/intermedia hasta que se migre a un &lt;code&gt;actor&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;El acceso a datos debe controlarse internamente con un &lt;code&gt;lock&lt;/code&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  ¿Qué riesgos concretos introduce el uso de &lt;code&gt;@unchecked Sendable&lt;/code&gt;?
&lt;/h3&gt;

&lt;p&gt;Puede ser que el día que se agregue &lt;code&gt;@unchecked Sendable&lt;/code&gt; a una clase esta en realidad sea segura para usar en un ambiente concurrente. Sin embargo, no hay certeza de que el día de mañana alguien agregue una funcionalidad a la clase y haya pasado por alto la sincronización de los hilos para acceder a los datos.&lt;/p&gt;

&lt;p&gt;Por ejemplo, considerar la clase:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight swift"&gt;&lt;code&gt;&lt;span class="kd"&gt;nonisolated&lt;/span&gt; &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="kt"&gt;ArticleTitlesCache&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kd"&gt;@unchecked&lt;/span&gt; &lt;span class="kt"&gt;Sendable&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;cacheMutatingLock&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kt"&gt;DispatchQueue&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;label&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;"cache.lock.queue"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

  &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="nv"&gt;articleTitles&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;Set&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;String&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;

  &lt;span class="kd"&gt;func&lt;/span&gt; &lt;span class="nf"&gt;addArticleTitle&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;_&lt;/span&gt; &lt;span class="nv"&gt;title&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;String&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;cacheMutatingLock&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;sync&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="n"&gt;_&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;articleTitles&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;insert&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;title&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="kd"&gt;func&lt;/span&gt; &lt;span class="nf"&gt;cachedArticleTitles&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="kt"&gt;Set&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;String&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;cacheMutatingLock&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;sync&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;articleTitles&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;El día de mañana, se quiere agregar una funcionalidad para contar el número de artículos almacenados que, idealmente, se construiría así:&lt;/p&gt;

&lt;p&gt;Alguien el día de mañana podría olvidar envolver con &lt;code&gt;cacheMutatingLock&lt;/code&gt; la nueva funcionalidad:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight swift"&gt;&lt;code&gt;&lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="nv"&gt;count&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;Int&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="n"&gt;cacheMutatingLock&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;sync&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;articleTitles&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;count&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Sin embargo, se pasó por alto la sincronización de los hilos y se escribió así:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight swift"&gt;&lt;code&gt;&lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="nv"&gt;count&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;Int&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="n"&gt;articleTitles&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;count&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  ¿Por qué el compilador no puede verificar la seguridad de hilos cuando se usa un &lt;code&gt;DispatchQueue&lt;/code&gt; como &lt;code&gt;lock&lt;/code&gt;?
&lt;/h3&gt;

&lt;p&gt;El compilador verifica que una implementación sea segura en términos de concurrencia de forma estructural y estática que implica el uso de valores inmutables, tipos de datos &lt;code&gt;Sendable&lt;/code&gt;, y sincronización de hilos por medio de dominios de aislamiento y &lt;code&gt;async/await&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Usar &lt;code&gt;DispatchQueue&lt;/code&gt; correctamente para sincronizar hilos requiere una convención de comportamiento en tiempo de ejecución - El día de mañana un desarrollador puede olvidar sincronizar los hilos con &lt;code&gt;DispatchQueue&lt;/code&gt; y el comportamiento se daña.&lt;/p&gt;

&lt;h3&gt;
  
  
  ¿Cuál es la alternativa recomendada a &lt;code&gt;@unchecked Sendable&lt;/code&gt; y por qué es superior?
&lt;/h3&gt;

&lt;p&gt;Se recomienda usar &lt;code&gt;Sendable&lt;/code&gt; (sin &lt;code&gt;@unchecked&lt;/code&gt;).&lt;/p&gt;

&lt;h2&gt;
  
  
  Recitación
&lt;/h2&gt;

&lt;h3&gt;
  
  
  ¿Puedes explicar con tus propias palabras qué ocurre si se accede a &lt;code&gt;articleTitles&lt;/code&gt; sin pasar por &lt;code&gt;cacheMutatingLock&lt;/code&gt;?
&lt;/h3&gt;

&lt;p&gt;Puede ocurrir una carrera de datos.&lt;/p&gt;

&lt;h3&gt;
  
  
  ¿Qué ventaja ofrece usar un &lt;code&gt;actor&lt;/code&gt; frente a un &lt;code&gt;lock&lt;/code&gt; manual?
&lt;/h3&gt;

&lt;p&gt;El &lt;code&gt;actor&lt;/code&gt; le da al compilador una garantía estructural: sabe por diseño que todo acceso a su estado está serializado.&lt;/p&gt;

&lt;h2&gt;
  
  
  Repaso
&lt;/h2&gt;

&lt;h3&gt;
  
  
  ¿En qué escenario específico el artículo acepta &lt;code&gt;@unchecked Sendable&lt;/code&gt; como solución válida, y qué condición impone para usarlo?
&lt;/h3&gt;

&lt;p&gt;Es válido poner &lt;code&gt;@unchecked Sendable&lt;/code&gt; es una clase que se sabe que es segura para usar en ambientes concurrentes (lo ha sido por mucho tiempo) y se programa una migración para convertirla en &lt;code&gt;actor&lt;/code&gt; (con un ticket, por ejemplo).&lt;/p&gt;

&lt;h3&gt;
  
  
  Si tuvieras que migrar &lt;code&gt;ArticleTitlesCache&lt;/code&gt; a un &lt;code&gt;actor&lt;/code&gt;, ¿qué cambios estructurales serían necesarios?
&lt;/h3&gt;

&lt;p&gt;Se elimina la sincronización con &lt;code&gt;DispatchQueue&lt;/code&gt; y todos los llamados de los clientes tendrían que cambiar para usar &lt;code&gt;await&lt;/code&gt;.&lt;/p&gt;




&lt;h2&gt;
  
  
  Bibliografía
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://courses.avanderlee.com/p/swift-concurrency" rel="noopener noreferrer"&gt;Van der Lee, A. (2025). &lt;em&gt;Swift Concurrency Course&lt;/em&gt; [Curso en línea]. avanderlee.com.&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>swift</category>
      <category>ios</category>
      <category>concurrency</category>
      <category>swiftconcurrency</category>
    </item>
    <item>
      <title>[SC] Closures con @Sendable</title>
      <dc:creator>GoyesDev</dc:creator>
      <pubDate>Thu, 09 Apr 2026 22:06:53 +0000</pubDate>
      <link>https://dev.to/david_goyes_a488f58a17a53/sc-closures-con-sendable-55ih</link>
      <guid>https://dev.to/david_goyes_a488f58a17a53/sc-closures-con-sendable-55ih</guid>
      <description>&lt;h2&gt;
  
  
  Preguntas
&lt;/h2&gt;

&lt;h3&gt;
  
  
  ¿Por qué no basta con el protocolo &lt;code&gt;Sendable&lt;/code&gt; para funciones y closures?
&lt;/h3&gt;

&lt;p&gt;Los closures y funciones pueden capturar valores. A la hora de usar un closure o una función en un entorno concurrente, es posible que sea necesario pasarlo a través de varios dominios de aislamiento y, por tanto, también se debe garantizar que los valores capturados sean seguros.&lt;/p&gt;

&lt;p&gt;Actualmente los closures y funciones no pueden conformar el protocolo &lt;code&gt;Sendable&lt;/code&gt;, sin embargo, la etiqueta &lt;code&gt;@Sendable&lt;/code&gt; le permite al compilador validar que el closure o función sea seguro para pasar entre dominios de aislamiento.&lt;/p&gt;

&lt;h3&gt;
  
  
  ¿Qué garantía ofrece &lt;code&gt;@Sendable&lt;/code&gt; al compilador sobre los valores capturados?
&lt;/h3&gt;

&lt;p&gt;&lt;code&gt;@Sendable&lt;/code&gt; garantiza que los valores capturados deben ser &lt;code&gt;Sendable&lt;/code&gt; y también deben ser capturados por valor. Esto último puede ser algo confuso inicialmente, sin embargo, espero poder aclararlo con los siguiente ejemplos:&lt;/p&gt;

&lt;p&gt;El siguiente closure captura un &lt;code&gt;Int&lt;/code&gt; escalar, así que tiene una referencia directa a su valor.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight swift"&gt;&lt;code&gt;&lt;span class="kd"&gt;func&lt;/span&gt; &lt;span class="nf"&gt;execute&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="kt"&gt;Int&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Puedo extraer el &lt;code&gt;Int&lt;/code&gt; escalar y moverlo a una constante por fuera. En este caso, el closure va a tener una copia del valor de esa constante. Una vez que termina el scope de &lt;code&gt;execute()&lt;/code&gt; la variable &lt;code&gt;x&lt;/code&gt; se libera del stack, mientras que el closure retornado va a conservar una copia del valor que tenía.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight swift"&gt;&lt;code&gt;&lt;span class="kd"&gt;func&lt;/span&gt; &lt;span class="nf"&gt;execute&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="kt"&gt;Int&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;x&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Si &lt;code&gt;x&lt;/code&gt; es una variable, Swift internamente genera una caja para almacenar el valor y poder referenciarla desde el closure después. En efectos prácticos, estaría moviendo un valor del stack al heap.&lt;/p&gt;

&lt;p&gt;Consideremos el siguiente código:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight swift"&gt;&lt;code&gt;&lt;span class="kd"&gt;func&lt;/span&gt; &lt;span class="nf"&gt;execute&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="kt"&gt;Int&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="nv"&gt;x&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Swift internamente haría lo siguiente:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight swift"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Swift crea un "box" en el heap para almacenar x&lt;/span&gt;
&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="kt"&gt;Box&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;T&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="nv"&gt;value&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;T&lt;/span&gt;
    &lt;span class="nf"&gt;init&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;_&lt;/span&gt; &lt;span class="nv"&gt;value&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;T&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;value&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;func&lt;/span&gt; &lt;span class="nf"&gt;execute&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="kt"&gt;Int&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;x&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kt"&gt;Box&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;En código de un solo hilo no habría ningún problema, sin embargo, si se marca &lt;code&gt;execute()&lt;/code&gt; con &lt;code&gt;@Sendable&lt;/code&gt;, entonces aparecería un error como el siguiente:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight swift"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Reference to captured var ‘x’ in concurrently-executing code &lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Por esta razón, hay que usar un capture list, para guardar una copia de la variable en la definición del closure. Esto sería un "snapshot".&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight swift"&gt;&lt;code&gt;&lt;span class="kd"&gt;func&lt;/span&gt; &lt;span class="nf"&gt;execute&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="kt"&gt;Int&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="nv"&gt;x&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  ¿Cuándo es necesario cruzar dominios de aislamiento (isolation domains) con una función?
&lt;/h3&gt;

&lt;p&gt;Como regla general, se dice que una función necesita cruzar un dominio de aislamiento cuando se crea en un dominio, pero se ejecuta en otro. Esta situación puede presentarse en los siguientes escenarios:&lt;/p&gt;

&lt;h4&gt;
  
  
  1. Pasar callbacks o predicados a un actor
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight swift"&gt;&lt;code&gt;&lt;span class="kd"&gt;actor&lt;/span&gt; &lt;span class="kt"&gt;OrdersStore&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;private(set)&lt;/span&gt; &lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="nv"&gt;orders&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="kt"&gt;Order&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;
  &lt;span class="kd"&gt;func&lt;/span&gt; &lt;span class="nf"&gt;filter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;_&lt;/span&gt; &lt;span class="nv"&gt;isIncluded&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kd"&gt;@Sendable&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;Order&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="kt"&gt;Bool&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="kt"&gt;Order&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;orders&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;filter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;isIncluded&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight swift"&gt;&lt;code&gt;&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;store&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kt"&gt;OrdersStore&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;expensiveOrders&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;store&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;filter&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="n"&gt;order&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="n"&gt;order&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;total&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;1000&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;En el caso anterior, se define el predicado en el contexto del invocador y se pasa al actor &lt;code&gt;OrdersStore&lt;/code&gt; cuando se invoca &lt;code&gt;await store.filter&lt;/code&gt;.&lt;/p&gt;

&lt;h4&gt;
  
  
  2. Tareas en segundo plano
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight swift"&gt;&lt;code&gt;&lt;span class="kd"&gt;actor&lt;/span&gt; &lt;span class="kt"&gt;ImageProcessor&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;func&lt;/span&gt; &lt;span class="nf"&gt;process&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;_&lt;/span&gt; &lt;span class="nv"&gt;image&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;UIImage&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="kt"&gt;UIImage&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="c1"&gt;// procesamiento pesado...&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;image&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;processor&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kt"&gt;ImageProcessor&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

&lt;span class="kd"&gt;func&lt;/span&gt; &lt;span class="nf"&gt;processInBackground&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="nv"&gt;image&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;UIImage&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; 
  &lt;span class="nv"&gt;transform&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kd"&gt;@escaping&lt;/span&gt; &lt;span class="kd"&gt;@Sendable&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;UIImage&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="kt"&gt;UIImage&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kt"&gt;Task&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;priority&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;background&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;transform&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;image&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;         &lt;span class="c1"&gt;// dominio de la Task&lt;/span&gt;
      &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;processor&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;process&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;       &lt;span class="c1"&gt;// dominio del actor&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;En el ejemplo anterior, el closure recibido por parámetro &lt;code&gt;transform&lt;/code&gt; se originó en el dominio del invocador y luego se pasó al dominio del &lt;code&gt;Task&lt;/code&gt;.&lt;/p&gt;

&lt;h4&gt;
  
  
  3. Programación funcional con actores
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight swift"&gt;&lt;code&gt;&lt;span class="kd"&gt;actor&lt;/span&gt; &lt;span class="kt"&gt;ProductCatalog&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;private(set)&lt;/span&gt; &lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="nv"&gt;products&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="kt"&gt;Product&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;

  &lt;span class="kd"&gt;func&lt;/span&gt; &lt;span class="nf"&gt;apply&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="nv"&gt;filter&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kd"&gt;@Sendable&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;Product&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="kt"&gt;Bool&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nv"&gt;transform&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kd"&gt;@Sendable&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;Product&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="kt"&gt;Product&lt;/span&gt;
  &lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="kt"&gt;Product&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;products&lt;/span&gt;
      &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;filter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;filter&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;map&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;transform&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight swift"&gt;&lt;code&gt;&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;catalog&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kt"&gt;ProductCatalog&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;discounted&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;catalog&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;apply&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="nv"&gt;filter&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nv"&gt;$0&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;stock&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="nv"&gt;transform&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;product&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt;
    &lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="nv"&gt;p&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;product&lt;/span&gt;
    &lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;price&lt;/span&gt; &lt;span class="o"&gt;*=&lt;/span&gt; &lt;span class="mf"&gt;0.9&lt;/span&gt;  &lt;span class="c1"&gt;// 10% de descuento&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;p&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;En este ejemplo, dos funciones de orden superior se crearon en el contexto invocador y luego se pasan al actor.&lt;/p&gt;

&lt;h4&gt;
  
  
  4. Código &lt;code&gt;nonisolated&lt;/code&gt; que delega trabajo a un actor
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight swift"&gt;&lt;code&gt;&lt;span class="kd"&gt;actor&lt;/span&gt; &lt;span class="kt"&gt;NotificationsStore&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;private(set)&lt;/span&gt; &lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="nv"&gt;notifications&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="kt"&gt;Notification&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;

    &lt;span class="kd"&gt;func&lt;/span&gt; &lt;span class="nf"&gt;removeAll&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;where&lt;/span&gt; &lt;span class="nv"&gt;condition&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kd"&gt;@Sendable&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;Notification&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="kt"&gt;Bool&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;notifications&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;removeAll&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;where&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;condition&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;extension&lt;/span&gt; &lt;span class="kt"&gt;NotificationsStore&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;nonisolated&lt;/span&gt; &lt;span class="kd"&gt;func&lt;/span&gt; &lt;span class="nf"&gt;cleanUpInBackground&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="n"&gt;_&lt;/span&gt; &lt;span class="nv"&gt;shouldRemove&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kd"&gt;@escaping&lt;/span&gt; &lt;span class="kd"&gt;@Sendable&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;Notification&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="kt"&gt;Bool&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="kt"&gt;Task&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;priority&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;background&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;removeAll&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;where&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;shouldRemove&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// Uso:&lt;/span&gt;
&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;notificationsStore&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kt"&gt;NotificationsStore&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="n"&gt;notificationsStore&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;cleanUpInBackground&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;notification&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt;
    &lt;span class="n"&gt;notification&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;isRead&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="n"&gt;notification&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;age&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;30&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A pesar de que Swift Concurrency define &lt;code&gt;nonisolated&lt;/code&gt; como un dominio de aislamiento, en principio no es un dominio propio porque no protege datos ni sincroniza acceso. Por eso, en principio, &lt;code&gt;cleanUpInBackground&lt;/code&gt; es código que vive fuera de cualquier actor. Luego, &lt;code&gt;shouldRemove&lt;/code&gt; viaja así:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Invocador a &lt;code&gt;nonisolated&lt;/code&gt;: el closure entra como parámetro a &lt;code&gt;cleanUpInBackground&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;nonisolated&lt;/code&gt; a &lt;code&gt;Task&lt;/code&gt;: el closure es capturado por el bloque &lt;code&gt;Task(priority: .background)&lt;/code&gt;, cruzando hacia el dominio de la tarea. Aquí es donde &lt;code&gt;@escaping&lt;/code&gt; y &lt;code&gt;@Sendable&lt;/code&gt; son necesarios.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;Task&lt;/code&gt; a &lt;code&gt;actor&lt;/code&gt;: el closure se pasa a &lt;code&gt;removeAll(where:)&lt;/code&gt; con &lt;code&gt;await&lt;/code&gt;, cruzando hacia el dominio del actor.&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  ¿Qué diferencia hay entre capturar una variable &lt;code&gt;let&lt;/code&gt; y una &lt;code&gt;var&lt;/code&gt; dentro de un closure &lt;code&gt;@Sendable&lt;/code&gt;?
&lt;/h3&gt;

&lt;p&gt;Cuando se captura un &lt;code&gt;var&lt;/code&gt; dentro de un closure, en realidad se envuelve el valor en una especie de caja que, en sentido práctico, mueve el valor del stack al heap. Como pasar esta referencia entre dominios de aislamiento es inseguro, al usar &lt;code&gt;@Sendable&lt;/code&gt; aparece el error de compilación:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight swift"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Reference to captured var ‘x’ in concurrently-executing code &lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  ¿Para qué sirve una capture list y cuándo es obligatorio usarla?
&lt;/h3&gt;

&lt;p&gt;Una capture list sirve para tomar una fotografía inmutable del valor de una variable en el momento en que se crea el closure, en lugar de capturar una referencia a esa variable, lo que satisface el requisito de inmutabilidad de &lt;code&gt;@Sendable&lt;/code&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  ¿Qué errores de compilación aparecen si se pasa un closure entre dominios de aislamiento sin marcarlo como &lt;code&gt;@Sendable&lt;/code&gt;?
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight swift"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Passing closure as a sending parameter risks causing data races between code in the current Task and the concurrent execution of the closure.&lt;/span&gt;

&lt;span class="c1"&gt;// Sending task-isolated value of type ‘(X) -&amp;gt; Y’ with later accesses to actor-isolated context risks causing data races &lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  ¿Cómo cambia el comportamiento del compilador al agregar &lt;code&gt;@Sendable&lt;/code&gt; al parámetro &lt;code&gt;shouldBeRemoved&lt;/code&gt;?
&lt;/h3&gt;

&lt;p&gt;El compilador puede verificar que los valores capturados por el closure sean &lt;code&gt;Sendable&lt;/code&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  ¿Por qué el compilador rechaza capturar una var de tipo String aunque String sea un value type?
&lt;/h3&gt;

&lt;p&gt;Porque cuando un closure captura una variable, se crea una caja que la mueve del stack al heap. Por esta razón, se tiene que trabajar con valores inmutables.&lt;/p&gt;

&lt;h3&gt;
  
  
  ¿Qué significa "capturar por valor" (capture by-value) y qué problema evita?
&lt;/h3&gt;

&lt;p&gt;Capturar por valor significa que el closure se queda con una copia independiente del valor en el momento de su creación, en lugar de mantener una referencia a la variable.&lt;/p&gt;

&lt;p&gt;Esto evita mutaciones inesperadas y carreras de datos. Por ejemplo:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight swift"&gt;&lt;code&gt;&lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="nv"&gt;counter&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;
&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;closure&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;counter&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="n"&gt;counter&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;99&lt;/span&gt;
&lt;span class="nf"&gt;closure&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="c1"&gt;// imprime 99, no 0&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Si se captura por valor pasa lo siguiente:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight swift"&gt;&lt;code&gt;&lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="nv"&gt;counter&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;
&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;closure&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;counter&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;counter&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="n"&gt;counter&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;99&lt;/span&gt;
&lt;span class="nf"&gt;closure&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="c1"&gt;// imprime 0 — trabaja con su propia copia&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Bibliografía
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://courses.avanderlee.com/p/swift-concurrency" rel="noopener noreferrer"&gt;Van der Lee, A. (2025). &lt;em&gt;Swift Concurrency Course&lt;/em&gt; [Curso en línea]. avanderlee.com.&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>swift</category>
      <category>ios</category>
      <category>swiftconcurrency</category>
      <category>concurrency</category>
    </item>
    <item>
      <title>[SC] Sendable y Tipos-por-referencia</title>
      <dc:creator>GoyesDev</dc:creator>
      <pubDate>Sat, 04 Apr 2026 16:18:51 +0000</pubDate>
      <link>https://dev.to/david_goyes_a488f58a17a53/sc-sendable-y-tipos-por-referencia-goa</link>
      <guid>https://dev.to/david_goyes_a488f58a17a53/sc-sendable-y-tipos-por-referencia-goa</guid>
      <description>&lt;h2&gt;
  
  
  Preguntas
&lt;/h2&gt;

&lt;h3&gt;
  
  
  ¿Qué es un tipo por referencia y en qué se diferencia fundamentalmente de un tipo por valor?
&lt;/h3&gt;

&lt;p&gt;Un tipo por referencia es una instancia que se manipula a través de punteros. Esto implica que cuando se modifica el valor a través un puntero, puede haber otro apuntando a la misma dirección de memoria que se vea "afectado".&lt;/p&gt;

&lt;p&gt;Los siguientes son tipos de dato por referencia:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Clases (&lt;code&gt;class&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;Closures (&lt;code&gt;(Input) -&amp;gt; (Output)&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;Actores (&lt;code&gt;actor&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;Metatipos (&lt;code&gt;MyStruct.Type&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;Protocolos con restricción a &lt;code&gt;class&lt;/code&gt; o &lt;code&gt;AnyObject&lt;/code&gt; (&lt;code&gt;protocol P: AnyObject { }&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;&lt;code&gt;NSObject&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Referencias de tipo &lt;code&gt;UnsafePointer&lt;/code&gt; &amp;amp; &lt;code&gt;Unmanaged&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  ¿Por qué las clases no pueden conformarse a &lt;code&gt;Sendable&lt;/code&gt; tan fácilmente como las estructuras?
&lt;/h3&gt;

&lt;p&gt;Puedo tener dos punteros apuntando a la misma dirección de memoria, y usar cada puntero desde un hilo diferente. En este caso podría haber un "data-race", si ambos hilos tratan de leer y modificar la misma posición de memoria simultáneamente.&lt;/p&gt;

&lt;h3&gt;
  
  
  ¿Qué condiciones debe cumplir una clase para poder marcarse como Sendable?
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight swift"&gt;&lt;code&gt;&lt;span class="c1"&gt;// ❌ Non-final class 'Counter' cannot conform to 'Sendable'; use '@unchecked Sendable'&lt;/span&gt;
&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="kt"&gt;Counter&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;Sendable&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;// ❌ Stored property 'value' of 'Sendable'-conforming class 'Counter' is mutable&lt;/span&gt;
  &lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="nv"&gt;value&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;Int&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Hay dos problemas en la clase anterior:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;No es &lt;code&gt;final&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Tiene un atributo mutable.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;El atributo mutable es un problema múltiples dominios de aislamiento potencialmente podrían tener acceso y modificar la misma dirección de memoria, con lo que se generaría un data-race.&lt;/p&gt;

&lt;p&gt;Para que una clase sea &lt;code&gt;Sendable&lt;/code&gt;, esta debe:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Ser &lt;code&gt;final&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Solo contener propiedades inmutables y &lt;code&gt;Sendable&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;No ser sub-&lt;code&gt;class&lt;/code&gt;, o únicamente sub-&lt;code&gt;class&lt;/code&gt; de &lt;code&gt;NSObject&lt;/code&gt;.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Cualquier otro caso (no ser &lt;code&gt;final&lt;/code&gt;, ser subclase, o tener propiedades mutables) también puede ser &lt;code&gt;@unchecked Sendable&lt;/code&gt;, y debe tener acceso sincronizado vía &lt;a href="https://developer.apple.com/documentation/foundation/nslocking" rel="noopener noreferrer"&gt;&lt;code&gt;NSLocking&lt;/code&gt;&lt;/a&gt;.&lt;/p&gt;

&lt;h4&gt;
  
  
  Convertir &lt;code&gt;class&lt;/code&gt; en &lt;code&gt;actor&lt;/code&gt;
&lt;/h4&gt;

&lt;p&gt;Otra alternativa puede ser tener un &lt;code&gt;actor&lt;/code&gt;, que automáticamente hace que el tipo de dato sea &lt;code&gt;Sendable&lt;/code&gt;, gracias a que los datos se sincronizan a través del executor del actor.&lt;/p&gt;

&lt;p&gt;Sin embargo, esto complica mucho la implementación cuando se quiere usar el &lt;code&gt;actor&lt;/code&gt; en un contexto de concurrencia sin aislamiento:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight swift"&gt;&lt;code&gt;&lt;span class="kd"&gt;actor&lt;/span&gt; &lt;span class="kt"&gt;X&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="nv"&gt;value&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;Int&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;struct&lt;/span&gt; &lt;span class="kt"&gt;XTests&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;@Test&lt;/span&gt;
  &lt;span class="kd"&gt;func&lt;/span&gt; &lt;span class="nf"&gt;execute&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;sut1&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kt"&gt;X&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;sut2&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;sut1&lt;/span&gt;

    &lt;span class="c1"&gt;// ❌ Actor-isolated property 'value' can not be mutated from a nonisolated context&lt;/span&gt;
    &lt;span class="n"&gt;sut2&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
    &lt;span class="c1"&gt;// ⚠️ Un actor es un dato por referencia&lt;/span&gt;
    &lt;span class="cp"&gt;#expect(sut1.value == 1)&lt;/span&gt;
    &lt;span class="c1"&gt;// ❌ Actor-isolated property 'value' can not be referenced from a nonisolated context&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Antes de convertir la clase en actor, vale la pena preguntarse:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;¿Este &lt;code&gt;class&lt;/code&gt; puede ser un &lt;code&gt;struct&lt;/code&gt; mejor?&lt;/li&gt;
&lt;li&gt;¿Este &lt;code&gt;class&lt;/code&gt; necesita ser mutable y no-&lt;code&gt;final&lt;/code&gt;?&lt;/li&gt;
&lt;li&gt;¿Este &lt;code&gt;class&lt;/code&gt; va a ser modificado desde distintos dominios de aislamiento? ¿O basta con marcarlo con &lt;code&gt;@MainActor&lt;/code&gt;?&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  ¿Por qué las clases no finales (non-&lt;code&gt;final&lt;/code&gt;) no pueden ser &lt;code&gt;Sendable&lt;/code&gt;?
&lt;/h3&gt;

&lt;p&gt;A pesar de que tenga una súper-clase que cumpla con las condiciones para ser &lt;code&gt;Sendable&lt;/code&gt;, el día de mañana podría aparecer una sub-clase que (1) agregue un atributo mutable o que (2) no sea &lt;code&gt;Sendable&lt;/code&gt;. En ese caso, el compilador ya no puede asegurar que no haya data-races. Si luego se referencian unas subclases no-&lt;code&gt;Sendable&lt;/code&gt; a través de la interfaz de la super-clase (por polimorfismo) que supuéstamente es &lt;code&gt;Sendable&lt;/code&gt;, entonces estaría incumpliendo con el contrato.&lt;/p&gt;

&lt;p&gt;Técnicamente se podría re-compilar todo el proyecto revisando todas las subclases; sin embargo, esto impactaría las optimizaciones de compilación.&lt;/p&gt;

&lt;h3&gt;
  
  
  ¿Cuál es la única superclase permitida en una clase &lt;code&gt;Sendable&lt;/code&gt;, y por qué?
&lt;/h3&gt;

&lt;p&gt;Solo se permite heredar de &lt;code&gt;NSObject&lt;/code&gt; al conformar &lt;code&gt;Sendable&lt;/code&gt;, porque puede haber protocolos de APIs basadas en Obj-C, que conforman &lt;code&gt;NSObjectProtocol&lt;/code&gt;, que requieren heredar de &lt;code&gt;NSObject&lt;/code&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  ¿Cómo puede la composición ayudar a crear tipos por referencia que sean &lt;code&gt;Sendable&lt;/code&gt;?
&lt;/h3&gt;

&lt;p&gt;Puede ser que nuestro API ya tenga un tipo de dato &lt;code&gt;class&lt;/code&gt; que sea &lt;code&gt;Sendable&lt;/code&gt; y nosotros necesitemos agregarle comportamiento. En este caso, debemos buscar añadirlo por composición.&lt;/p&gt;




&lt;h2&gt;
  
  
  Lectura, recitación y repaso
&lt;/h2&gt;

&lt;h3&gt;
  
  
  ¿Qué alternativas existen antes de convertir una clase en un actor para resolver problemas de concurrencia?
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;¿La clase puede ser &lt;code&gt;struct&lt;/code&gt;?&lt;/li&gt;
&lt;li&gt;¿Necesita ser mutable? ¿Puede ser &lt;code&gt;final&lt;/code&gt;?&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  ¿Por qué el compilador no puede simplemente validar todos los casos de uso de una clase no final para determinar si es segura como &lt;code&gt;Sendable&lt;/code&gt;?
&lt;/h3&gt;

&lt;p&gt;Se pierden optimizaciones de compilación.&lt;/p&gt;

&lt;h3&gt;
  
  
  ¿En qué situación tendría sentido usar &lt;code&gt;@MainActor&lt;/code&gt; en lugar de convertir una clase en actor?
&lt;/h3&gt;

&lt;p&gt;Convertir una clase en actor provocaría que tenga que acceder con &lt;code&gt;await&lt;/code&gt; a los datos desde contextos de concurrencia sin aislamiento.&lt;/p&gt;

&lt;p&gt;En ciertos escenarios sabemos que vamos a modificar la clase solo desde el hilo principal, así que podemos marcarla solo con &lt;code&gt;@MainActor&lt;/code&gt;.&lt;/p&gt;




&lt;h2&gt;
  
  
  Bibliografía
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://courses.avanderlee.com/p/swift-concurrency" rel="noopener noreferrer"&gt;Van der Lee, A. (2025). &lt;em&gt;Swift Concurrency Course&lt;/em&gt; [Curso en línea]. avanderlee.com.&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>swift</category>
      <category>ios</category>
      <category>concurrency</category>
      <category>swiftconcurrency</category>
    </item>
    <item>
      <title>[SC] Sendable y Tipos-por-valor</title>
      <dc:creator>GoyesDev</dc:creator>
      <pubDate>Sat, 04 Apr 2026 14:49:19 +0000</pubDate>
      <link>https://dev.to/david_goyes_a488f58a17a53/sc-sendable-y-tipos-por-valor-1kl6</link>
      <guid>https://dev.to/david_goyes_a488f58a17a53/sc-sendable-y-tipos-por-valor-1kl6</guid>
      <description>&lt;h2&gt;
  
  
  Preguntas
&lt;/h2&gt;

&lt;h3&gt;
  
  
  ¿Qué son los value types en Swift y cómo se diferencian de los reference types?
&lt;/h3&gt;

&lt;p&gt;Una instancia de un "value-type" mantiene una única copia de sus datos. Cuando se asigna a una variable o se pasa a una función, se crea una copia.&lt;/p&gt;

&lt;p&gt;Por otro lado, una sola instancia de un "reference-type" puede ser referenciada por varios punteros. Al asignarse a una variable o pasarse a una función, se pasa una referencia a la misma posición de memoria.&lt;/p&gt;

&lt;h3&gt;
  
  
  ¿Cuándo un &lt;code&gt;struct&lt;/code&gt; o &lt;code&gt;enum&lt;/code&gt; recibe conformidad implícita a &lt;code&gt;Sendable&lt;/code&gt;?
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;struct&lt;/code&gt; o &lt;code&gt;enum&lt;/code&gt; que no sea &lt;code&gt;public&lt;/code&gt; y no esté marcado con &lt;code&gt;@usableFromInline&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;struct&lt;/code&gt; o &lt;code&gt;enum&lt;/code&gt; congeladas ("frozen"), incluso si son públicas.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;La siguiente &lt;code&gt;struct&lt;/code&gt; es &lt;code&gt;Sendable&lt;/code&gt; por defecto:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight swift"&gt;&lt;code&gt;&lt;span class="c1"&gt;// ✅ Conforma Sendable por implícitamente&lt;/span&gt;
&lt;span class="kd"&gt;struct&lt;/span&gt; &lt;span class="kt"&gt;Person&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="nv"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;String&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Si se la hace &lt;code&gt;public&lt;/code&gt; deja de serlo:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight swift"&gt;&lt;code&gt;&lt;span class="c1"&gt;// ❌ NO es Sendable de forma implícita&lt;/span&gt;
&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;struct&lt;/span&gt; &lt;span class="kt"&gt;Person&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="nv"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;String&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Debido a que Swift oculta los detalles internos (como las variables privadas) de los tipos de datos públicos, el compilador es incapaz de verificar automáticamente que sea "thread-safe". Para curarse en salud, obliga al desarrollador a conformar &lt;code&gt;Sendable&lt;/code&gt; de forma explícita.&lt;/p&gt;

&lt;h3&gt;
  
  
  ¿Cómo influye &lt;code&gt;@usableFromInline&lt;/code&gt; en la conformidad implícita de &lt;code&gt;Sendable&lt;/code&gt;?
&lt;/h3&gt;

&lt;p&gt;Cuando el compilador puede garantizar que un &lt;code&gt;struct&lt;/code&gt; exista solo dentro de un módulo específico (i.e. no es &lt;code&gt;public&lt;/code&gt;), entonces "regala" un &lt;code&gt;Sendable&lt;/code&gt; implícito. En caso contrario, el desarrollador debe decidir explícitamente si conforma &lt;code&gt;Sendable&lt;/code&gt; o no.&lt;/p&gt;

&lt;p&gt;Lo anterior se debe hacer para tener una especie de "contrato" con los clientes del API:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Si el compilador infiere &lt;code&gt;Sendable&lt;/code&gt; implícito en un &lt;code&gt;struct&lt;/code&gt; &lt;code&gt;public&lt;/code&gt; y luego el tipo de dato cambia, el contrato se rompe en los clientes que ya lo usaban como &lt;code&gt;Sendable&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Al obligar al desarrollador a conformar &lt;code&gt;Sendable&lt;/code&gt; de forma explícita, si el día de mañana el tipo de dato cambia, el compilador primero se estalla al compilar el API.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Ahora bien, &lt;code&gt;@usableFromInline&lt;/code&gt; le permite a otros módulos clientes usar el tipo de dato dentro del código &lt;code&gt;@inlinable&lt;/code&gt;. Cuando un código se hace de tipo "inline", el cliente copia el código fuente en tiempo de compilación. Si al principio se usaba el tipo de dato como &lt;code&gt;Sendable&lt;/code&gt; y luego cambia, entonces se rompería el contrato en los clientes.&lt;/p&gt;

&lt;h3&gt;
  
  
  ¿Por qué los &lt;code&gt;enums&lt;/code&gt; públicos no marcados como &lt;code&gt;@frozen&lt;/code&gt; no son implícitamente &lt;code&gt;Sendable&lt;/code&gt;?
&lt;/h3&gt;

&lt;p&gt;Cuando un &lt;code&gt;struct&lt;/code&gt; o &lt;code&gt;enum&lt;/code&gt; es marcado como &lt;code&gt;public&lt;/code&gt;, el compilador no lo puede marcar implícitamente como &lt;code&gt;Sendable&lt;/code&gt; porque no puede garantizar que el día de mañana se le agregue un miembro que no sea &lt;code&gt;Sendable&lt;/code&gt; y rompa el contrato. Por esta razón, el desarrollador debe marcar el tipo de dato con &lt;code&gt;Sendable&lt;/code&gt; de forma explícita para que el compilador pueda analizarlo.&lt;/p&gt;

&lt;p&gt;Sin embargo, cuando un &lt;code&gt;struct&lt;/code&gt; o &lt;code&gt;enum&lt;/code&gt; es marcado con &lt;code&gt;@frozen&lt;/code&gt;, el desarrollador está asegurando que la interfaz del tipo de dato no va a cambiar en el futuro. En este caso, el compilador puede marcarlo como &lt;code&gt;Sendable&lt;/code&gt; de forma implícita, si los miembros también son &lt;code&gt;Sendable&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;El "Modelo de Evolución de Bibliotecas" (&lt;a href="https://www.swift.org/blog/library-evolution/" rel="noopener noreferrer"&gt;"Library Evolution Model"&lt;/a&gt;) permite al cliente de una biblioteca cargar una nueva versión de la biblioteca sin necesidad de recompilar otra vez el módulo.&lt;/p&gt;

&lt;p&gt;Los &lt;code&gt;enum&lt;/code&gt;s son el caso más delicado. Supongamos que construimos una biblioteca v1, con un enum:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight swift"&gt;&lt;code&gt;&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;enum&lt;/span&gt; &lt;span class="kt"&gt;Resultado&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="nf"&gt;exito&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;String&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="nf"&gt;error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;String&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Se puede compilar el siguiente cliente contra la biblioteca v1 y todo funciona.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight swift"&gt;&lt;code&gt;&lt;span class="c1"&gt;// ✅ El compilador está satisfecho porque se cubren todos los casos&lt;/span&gt;
&lt;span class="k"&gt;switch&lt;/span&gt; &lt;span class="n"&gt;resultado&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;exito&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;result&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="c1"&gt;// ...&lt;/span&gt;
  &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;error&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="c1"&gt;// ...&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Meses después, hago el siguiente cambio en &lt;code&gt;Resultado&lt;/code&gt; y lanzo v2:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight swift"&gt;&lt;code&gt;&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;enum&lt;/span&gt; &lt;span class="kt"&gt;Resultado&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="nf"&gt;exito&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;String&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="nf"&gt;error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;String&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="n"&gt;pendiente&lt;/span&gt; &lt;span class="c1"&gt;// ⚠️ Nuevo caso&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;En tiempo de ejecución el cliente carga v2 y de repente el &lt;code&gt;switch&lt;/code&gt; encuentra &lt;code&gt;.pendiente&lt;/code&gt;, un caso que no existe en el binario compilado. Esto es un comportamiento indefinido.&lt;/p&gt;

&lt;p&gt;Marcar el &lt;code&gt;enum&lt;/code&gt; como &lt;code&gt;@frozen&lt;/code&gt; asegura que el contrato público nunca va a cambiar.&lt;/p&gt;

&lt;p&gt;La relación entre &lt;code&gt;@frozen&lt;/code&gt; y &lt;code&gt;Sendable&lt;/code&gt; es que cuando se tiene un &lt;code&gt;enum&lt;/code&gt; cuyos miembros iniciales son &lt;code&gt;Sendable&lt;/code&gt;, pero no está marcado como &lt;code&gt;@frozen&lt;/code&gt;, el compilador no puede asegurar que el día de mañana aparezca un nuevo caso que no sea &lt;code&gt;Sendable&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Por ejemplo, el día de mañana podríamos tener una nueva propiedad &lt;code&gt;pendiente1&lt;/code&gt; que envuelva una instancia de tipo &lt;code&gt;MiClase&lt;/code&gt; que no es &lt;code&gt;Sendable&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight swift"&gt;&lt;code&gt;&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="kt"&gt;MiClase&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="nv"&gt;contador&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="c1"&gt;// ❌ Las clases son no-Sendable por defecto&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;enum&lt;/span&gt; &lt;span class="kt"&gt;Resultado&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="nf"&gt;exito&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;String&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="nf"&gt;error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;String&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="nf"&gt;pendiente1&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;MiClase&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c1"&gt;// ⚠️ Nuevo caso no-Sendable&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  ¿Qué significa que todos los miembros de un tipo deben ser &lt;code&gt;Sendable&lt;/code&gt;?
&lt;/h3&gt;

&lt;p&gt;Si un tipo de dato es &lt;code&gt;Sendable&lt;/code&gt;, todos los atributos deben ser &lt;code&gt;Sendable&lt;/code&gt; también. Si pongo uno que no lo sea, el compilador sacará el error: &lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;Stored property ‘x_instance‘ of ‘Sendable’-conforming struct ‘Y’ has non-sendable type ‘X’&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  ¿Cuáles son las alternativas si un miembro no puede ser marcado como &lt;code&gt;Sendable&lt;/code&gt;?
&lt;/h3&gt;

&lt;p&gt;Si tenemos una dependencia que no puede ser marcada como &lt;code&gt;Sendable&lt;/code&gt; porque posiblemente es un tercero que no podemos modificar, entonces podríamos usar una de las siguientes alternativas:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Marcar el tipo de dato que estamos definiendo como &lt;code&gt;@unchecked Sendable&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Revisar cómo se se está usando la dependencia para tener una referencia indirecta a ella.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Por ejemplo, en el siguiente caso, &lt;code&gt;Location&lt;/code&gt; &lt;strong&gt;no&lt;/strong&gt; es &lt;code&gt;Sendable&lt;/code&gt;. Sin embargo, podemos tener una referencia a un &lt;code&gt;Location&lt;/code&gt; por medio de su nombre:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight swift"&gt;&lt;code&gt;&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;struct&lt;/span&gt; &lt;span class="kt"&gt;Person&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;Sendable&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="nv"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;String&lt;/span&gt;
  &lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="nv"&gt;hometown&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;String&lt;/span&gt;

  &lt;span class="nf"&gt;init&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;String&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;hometown&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;Location&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt;
    &lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;hometown&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;hometown&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;struct&lt;/span&gt; &lt;span class="kt"&gt;Location&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="nv"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;String&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  ¿Cómo se puede usar un actor para hacer un tipo &lt;code&gt;Sendable&lt;/code&gt;?
&lt;/h3&gt;

&lt;p&gt;Un actor es un guardan que serializa el acceso a su estado. Solo permite que una tarea a la vez acceda a sus datos.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight swift"&gt;&lt;code&gt;&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;struct&lt;/span&gt; &lt;span class="kt"&gt;Location&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="nv"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;String&lt;/span&gt;  &lt;span class="c1"&gt;// ❌ String público sin @frozen, no es Sendable implícito&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;struct&lt;/span&gt; &lt;span class="kt"&gt;LocationDetailViewModel&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;location&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;Location&lt;/span&gt;  &lt;span class="c1"&gt;// ❌ contiene un tipo no-Sendable&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;LocationDetailViewModel&lt;/code&gt; no puede ser &lt;code&gt;Sendable&lt;/code&gt; porque &lt;code&gt;Location&lt;/code&gt; tampoco lo es y Swift no puede garantizar que sea seguro compartirlo entre hilos.&lt;/p&gt;

&lt;p&gt;Si todo el acceso a &lt;code&gt;LocationDetailViewModel&lt;/code&gt; está garantizado que ocurre en el mismo actor, entonces nunca habrá dos hilos accediendo simultáneamente. El actor es el mecanismo de sincronización.&lt;/p&gt;

&lt;p&gt;Por lo tanto, Swift puede inferir &lt;code&gt;Sendable&lt;/code&gt; automáticamente - no porque el contenido sea seguro por sí solo, sino porque el acceso está controlado.&lt;/p&gt;

&lt;h3&gt;
  
  
  ¿Qué es &lt;code&gt;@MainActor&lt;/code&gt; y cómo simplifica la conformidad a &lt;code&gt;Sendable&lt;/code&gt;?
&lt;/h3&gt;

&lt;p&gt;&lt;code&gt;@MainActor&lt;/code&gt; asegura que el código se accede únicamente a través del hilo principal y es útil para componentes como &lt;code&gt;View&lt;/code&gt;s o &lt;code&gt;ViewModel&lt;/code&gt;s.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;@MainActor&lt;/code&gt; se encarga de la sincronización de los hilos, asegurando el acceso a un dato. Como Swift está satisfecho de que no habrá data-races con el tipo de dato marcado con &lt;code&gt;@MainActor&lt;/code&gt;, entonces le otorga &lt;code&gt;Sendable&lt;/code&gt; implícitamente.&lt;/p&gt;




&lt;h2&gt;
  
  
  Recitar
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Describe el concepto de copy-on-write (COW)
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://en.wikipedia.org/wiki/Copy-on-write" rel="noopener noreferrer"&gt;"Copy-on-write"&lt;/a&gt; es una optimización de rendimiento que usa Swift para colecciones de tipo por valor.&lt;/p&gt;

&lt;p&gt;Teóricamente, los tipos por valor se copian al asignarse:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight swift"&gt;&lt;code&gt;&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;a&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;6&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;7&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;8&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;9&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;b&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="c1"&gt;// ⚠️ Teóricamente se copia pero, ¿y en la práctica?&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Si cada asignación copiara el contenido real, trabajar con colecciones grandes sería muy costoso. Por esta razón, en lugar de copiar inmediatamente, Swift hace que &lt;code&gt;a&lt;/code&gt; y &lt;code&gt;b&lt;/code&gt; apunten al mismo buffer en memoria. La copia real ocurre solo cuando uno de los dos intenta modificar el contenido:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight swift"&gt;&lt;code&gt;&lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="nv"&gt;a&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="nv"&gt;b&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="c1"&gt;// 😱 mismo buffer, sin copia aún&lt;/span&gt;

&lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c1"&gt;// ✅ aquí ocurre la copia real&lt;/span&gt;
            &lt;span class="c1"&gt;// ahora b tiene su propio buffer&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Antes del &lt;code&gt;append&lt;/code&gt;, ambos comparten memoria. En el momento de la mutación, Swift detecta que hay más de un dueño y hace la copia. Internamente, Swift usa un conteo de referencias sobre el buffer interno y, antes de mutar, pregunta: ¿Soy el único dueño de este buffer? Si la respuesta es afirmativa: muto directamente sin copiar. Si la respuesta es negativa: copio primero y luego muto.&lt;/p&gt;

&lt;p&gt;CoW da:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Semántica de valor:&lt;/strong&gt; &lt;code&gt;a&lt;/code&gt; y &lt;code&gt;b&lt;/code&gt; se comportan como copias independientes.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Rendimiento de referencia:&lt;/strong&gt; no se paga el costo de la copia hasta que realmente se necesita.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;En muchos casos no se paga el costo de la copia - Por ejemplo, si se pasa un arreglo a una función que solo lo lee, jamás se copia.&lt;/p&gt;

&lt;h3&gt;
  
  
  ¿Por qué Swift requiere conformidad explícita a &lt;code&gt;Sendable&lt;/code&gt; para tipos públicos?
&lt;/h3&gt;

&lt;p&gt;Los clientes de mi API van a asumir que cierto tipo de dato es &lt;code&gt;Sendable&lt;/code&gt;. Si el día de mañana agrego un miembro que &lt;strong&gt;NO es&lt;/strong&gt; &lt;code&gt;Sendable&lt;/code&gt;, entonces mi API va a cambiar y mis clientes ya no podrán compilar. Por esta razón, yo debo declarar explícitamente que mi tipo de dato es &lt;code&gt;Sendable&lt;/code&gt; cuando lo hago &lt;code&gt;public&lt;/code&gt;.&lt;/p&gt;




&lt;h2&gt;
  
  
  Repaso
&lt;/h2&gt;

&lt;h3&gt;
  
  
  ¿Cuál es la diferencia entre un &lt;code&gt;struct&lt;/code&gt; implícitamente &lt;code&gt;Sendable&lt;/code&gt; y uno explícitamente &lt;code&gt;Sendable&lt;/code&gt;?
&lt;/h3&gt;

&lt;h3&gt;
  
  
  ¿Por qué &lt;code&gt;@frozen&lt;/code&gt; permite conformidad implícita a Sendable para tipos públicos?
&lt;/h3&gt;

&lt;h3&gt;
  
  
  Resumen: ¿Cuáles son los tres mecanismos principales para garantizar que un tipo sea &lt;code&gt;Sendable&lt;/code&gt;?
&lt;/h3&gt;




&lt;h2&gt;
  
  
  Bibliografía
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://courses.avanderlee.com/p/swift-concurrency" rel="noopener noreferrer"&gt;Van der Lee, A. (2025). &lt;em&gt;Swift Concurrency Course&lt;/em&gt; [Curso en línea]. avanderlee.com.&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>swift</category>
      <category>ios</category>
      <category>concurrency</category>
      <category>swiftconcurrency</category>
    </item>
    <item>
      <title>[SC] Conformar el protocolo Sendable</title>
      <dc:creator>GoyesDev</dc:creator>
      <pubDate>Fri, 03 Apr 2026 12:38:15 +0000</pubDate>
      <link>https://dev.to/david_goyes_a488f58a17a53/sc-conformar-el-protocolo-sendable-21o4</link>
      <guid>https://dev.to/david_goyes_a488f58a17a53/sc-conformar-el-protocolo-sendable-21o4</guid>
      <description>&lt;h2&gt;
  
  
  Preguntas guía
&lt;/h2&gt;

&lt;h3&gt;
  
  
  ¿Qué garantiza el protocolo &lt;code&gt;Sendable&lt;/code&gt; al compilador sobre un tipo?
&lt;/h3&gt;

&lt;p&gt;&lt;code&gt;Sendable&lt;/code&gt; es un tipo de dato que le dice a un compilador que es "thread-safe", y se puede transmitir entre dominios de aislamiento de forma segura (sin introducir un "data-race").&lt;/p&gt;

&lt;h3&gt;
  
  
  ¿Por qué una clase no-final no puede conformar &lt;code&gt;Sendable&lt;/code&gt; de forma directa?
&lt;/h3&gt;

&lt;p&gt;Una clase no-final puede tener sub-clases que introduzcan cambios inseguros, por lo que no se puede asegurar que sea "thread-safe".&lt;/p&gt;

&lt;p&gt;Así mismo, a pesar de que una clase no-final pueda ser inmutable o tener miembros &lt;code&gt;Sendable&lt;/code&gt;, puede ser que una sub-clase agregue miembros que no sean &lt;code&gt;Sendable&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Se puede usar &lt;code&gt;@unchecked Sendable&lt;/code&gt; en clases no-finales, sin embargo, esto implica que el desarrollador debe garantizar que la clase es "thread-safe", incluyendo a todas las sub-clases - Debido al inmenso y delicado trabajo que esto representa, no es recomendable.&lt;/p&gt;

&lt;h3&gt;
  
  
  ¿Qué condición debe cumplirse para que una propiedad &lt;code&gt;var&lt;/code&gt; en una clase sea compatible con &lt;code&gt;Sendable&lt;/code&gt;?
&lt;/h3&gt;

&lt;p&gt;Para que una propiedad &lt;code&gt;var&lt;/code&gt; sea compatible con &lt;code&gt;Sendable&lt;/code&gt;, debe ser modificada con un "lock".&lt;/p&gt;

&lt;h3&gt;
  
  
  ¿Qué entidades de Swift se pueden marcar como &lt;code&gt;Sendable&lt;/code&gt;?
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;em&gt;Tipos-por-referencia&lt;/em&gt; y &lt;em&gt;clases finales&lt;/em&gt; sin estado mutable.&lt;/li&gt;
&lt;li&gt;
&lt;em&gt;Tipos-por-referencia&lt;/em&gt; y &lt;em&gt;clases finales&lt;/em&gt; que manejan el acceso a su estado internamente (con "locks").&lt;/li&gt;
&lt;li&gt;
&lt;em&gt;Tipos-por-valor&lt;/em&gt; como &lt;code&gt;struct&lt;/code&gt; o &lt;code&gt;enum&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;em&gt;Funciones&lt;/em&gt; o &lt;em&gt;closures&lt;/em&gt; marcadas con &lt;code&gt;@Sendable&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  ¿Por qué la conformancia a &lt;code&gt;Sendable&lt;/code&gt; debe declararse en el mismo archivo fuente donde se define el tipo?
&lt;/h3&gt;

&lt;p&gt;&lt;code&gt;Sendable&lt;/code&gt; necesita ver todas las propiedades almacenadas para verificar que cierto tipo de dato puede ser transmitido de forma segura entre dominios de datos.&lt;/p&gt;

&lt;p&gt;--&lt;/p&gt;

&lt;h2&gt;
  
  
  Compresión profunda
&lt;/h2&gt;

&lt;h3&gt;
  
  
  ¿Qué diferencia hay entre &lt;code&gt;Sendable&lt;/code&gt; y &lt;code&gt;@unchecked Sendable&lt;/code&gt;, y cuándo se justifica usar el segundo?
&lt;/h3&gt;

&lt;p&gt;&lt;code&gt;Sendable&lt;/code&gt; significa que se garantiza que un tipo de dato es seguro para transmitirse entre dominios de aislamiento.&lt;/p&gt;

&lt;p&gt;Conformar &lt;code&gt;Sendable&lt;/code&gt; solamente, es una especie de contrato que indica que el compilador garantiza que el dato es "thread-safe". Por otro lado, usar &lt;code&gt;@unchecked Sendable&lt;/code&gt; implica que el dato es "thread-safe", pero que no es garantizado por el compilador, sino por el desarrollador.&lt;/p&gt;

&lt;p&gt;Se justifica usar &lt;code&gt;@unchecked Sendable&lt;/code&gt; en una clase no-final, con miembros mutables por medio de "locks".&lt;/p&gt;

&lt;h3&gt;
  
  
  ¿Cómo afecta el hecho de que una clase sea un reference type a su elegibilidad para &lt;code&gt;Sendable&lt;/code&gt;?
&lt;/h3&gt;

&lt;p&gt;Debido a que un objeto es reference-type, este puede ser modificado desde varios hilos. Si tiene miembros mutables, entonces no se puede garantizar que sea seguro para transmitirse entre dominios de aislamiento. Por esta razón, en caso de ser &lt;code&gt;Sendable&lt;/code&gt;, debe ponerse &lt;code&gt;@unchecked&lt;/code&gt; para indicar que es el desarrollador quien asegura que es seguro y no el compilador.&lt;/p&gt;

&lt;p&gt;Por otro lado, los miembros mutables deben ser modificados a través de "locks" e, idealmente, la clase debería ser &lt;code&gt;final&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Retención
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Sin releer el artículo, ¿puedes enumerar al menos cuatro tipos de entidades Swift que pueden marcarse como &lt;code&gt;Sendable&lt;/code&gt;?
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Funciones y closures marcados con &lt;code&gt;@Sendable&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Tipos de valor &lt;code&gt;struct&lt;/code&gt; y &lt;code&gt;enum&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Tipos de referencia (no-&lt;code&gt;final&lt;/code&gt; y &lt;code&gt;final&lt;/code&gt;) con datos inmutables o protegidos con locks.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  ¿Qué problema concreto introduce un &lt;code&gt;var&lt;/code&gt; no protegido en una clase que intenta conformar &lt;code&gt;Sendable&lt;/code&gt;?
&lt;/h3&gt;

&lt;p&gt;La variable puede ser modificada desde varios hilos simultáneamente.&lt;/p&gt;

&lt;h2&gt;
  
  
  Evaluación crítica
&lt;/h2&gt;

&lt;h3&gt;
  
  
  ¿Por qué el artículo desaconseja el uso de &lt;code&gt;@unchecked Sendable&lt;/code&gt; y qué alternativas propone?
&lt;/h3&gt;

&lt;p&gt;El artículo propone usar composición, clases finales o value-types.&lt;/p&gt;




&lt;h2&gt;
  
  
  Bibliografía
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://courses.avanderlee.com/p/swift-concurrency" rel="noopener noreferrer"&gt;Van der Lee, A. (2025). &lt;em&gt;Swift Concurrency Course&lt;/em&gt; [Curso en línea]. avanderlee.com.&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>swift</category>
      <category>ios</category>
      <category>swiftconcurrency</category>
      <category>concurrency</category>
    </item>
    <item>
      <title>[SC] Condición de carrera vs. Carrera de datos</title>
      <dc:creator>GoyesDev</dc:creator>
      <pubDate>Wed, 18 Mar 2026 15:20:05 +0000</pubDate>
      <link>https://dev.to/david_goyes_a488f58a17a53/sc-condicion-de-carrera-vs-carrera-de-datos-nai</link>
      <guid>https://dev.to/david_goyes_a488f58a17a53/sc-condicion-de-carrera-vs-carrera-de-datos-nai</guid>
      <description>&lt;h2&gt;
  
  
  1. ¿De qué trata el artículo en términos generales?
&lt;/h2&gt;

&lt;p&gt;"data race", "race condition", el uso de actores para evitar "data race", cómo SC no es capaz de resolver "race condition".&lt;/p&gt;

&lt;h2&gt;
  
  
  2. ¿Cuáles son los dos conceptos principales que se comparan?
&lt;/h2&gt;

&lt;p&gt;carrera de acceso a datos ("data race") vs condición de carrera ("race condition")&lt;/p&gt;

&lt;h2&gt;
  
  
  3. ¿Qué es exactamente un data race y bajo qué condiciones ocurre?
&lt;/h2&gt;

&lt;p&gt;Una carrera de acceso a datos ocurre cuando varios hilos tratan de acceder a una porción de memoria compartida sin la sincronización adecuada, donde al menos uno de ellos provoca una mutación.&lt;/p&gt;

&lt;p&gt;En el artículo aparece el siguiente ejemplo. Aunque teóricamente entiendo cómo puede fallar, en la práctica no logré obtener una carrera de datos.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight swift"&gt;&lt;code&gt;&lt;span class="kd"&gt;nonisolated&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="kt"&gt;DataRaceDemonstrator&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;

  &lt;span class="kd"&gt;func&lt;/span&gt; &lt;span class="nf"&gt;demonstrate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;_&lt;/span&gt; &lt;span class="nv"&gt;result&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kd"&gt;@escaping&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;Int&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;())&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="nv"&gt;counter&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;
    &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;queue&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kt"&gt;DispatchQueue&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;global&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;qos&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;background&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;_&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="o"&gt;...&lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="n"&gt;queue&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="c1"&gt;// ⚠️ Mutation of captured var 'counter' in&lt;/span&gt;
        &lt;span class="c1"&gt;// concurrently-executing code&lt;/span&gt;
        &lt;span class="n"&gt;counter&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="kt"&gt;DispatchQueue&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;main&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;asyncAfter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;deadline&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;now&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nf"&gt;result&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;counter&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Por un momento Xcode me mostró la siguiente advertencia que podría ser útil para detectar una carrera de datos:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Mutation of captured var 'counter' in concurrently-executing code&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Según el artículo, se puede validar que hay una carrera de datos al activar el "Thread Sanitizer" en las herramientas de diagnóstico en "Edit Schemes".&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fljy7q46shj99xx8u494z.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fljy7q46shj99xx8u494z.png" alt="Thread Sanitizer" width="800" height="365"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Es muy difícil detectar una carrera de datos porque:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Determinar que hace falta sincronización es difícil. Depende de la experiencia del desarrollador.&lt;/li&gt;
&lt;li&gt;El código inseguro no necesariamente falla en producción.&lt;/li&gt;
&lt;li&gt;Las fallas en runtime son difíciles de reproducir.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Escribí la siguiente prueba automatizada para probar el código de arriba:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight swift"&gt;&lt;code&gt;&lt;span class="kd"&gt;struct&lt;/span&gt; &lt;span class="kt"&gt;DataRaceDemonstratorTests&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;

  &lt;span class="kd"&gt;@Test&lt;/span&gt;
  &lt;span class="kd"&gt;func&lt;/span&gt; &lt;span class="nf"&gt;exec&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;sut&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kt"&gt;DataRaceDemonstrator&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

    &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;withCheckedContinuation&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;continuation&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt;
      &lt;span class="n"&gt;sut&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;demonstrate&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt;
        &lt;span class="n"&gt;continuation&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;resume&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;returning&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="cp"&gt;#expect(result == 10)&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;La solución que plantea el artículo es cambiar la cola global concurrente por una serial. Sin embargo, todavía tiene la desventaja de que se deben acceder a los datos con &lt;code&gt;serialQueue.async&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight swift"&gt;&lt;code&gt;&lt;span class="c1"&gt;// let queue = DispatchQueue.global(qos: .background)&lt;/span&gt;
&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;serialQueue&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kt"&gt;DispatchQueue&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;label&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;"com.example.serial"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="c1"&gt;// ...&lt;/span&gt;
&lt;span class="n"&gt;serialQueue&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="n"&gt;counter&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  4. ¿Qué es una race condition y en qué se diferencia de un data race?
&lt;/h2&gt;

&lt;p&gt;Un &lt;strong&gt;data race&lt;/strong&gt; ocurre cuando múltiples hilos tratan de acceder a una porción de memoria compartida y al menos uno de ellos está modificando, sin ningún tipo de sincronización. &lt;strong&gt;Es un problema de sincronización de acceso.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Un &lt;strong&gt;race condition&lt;/strong&gt; ocurre cuando el resultado del programa depende del orden de ejecución de las tareas y ese orden no se puede garantizar. &lt;strong&gt;Es un problema de orden de ejecución&lt;/strong&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  5. ¿Cómo resuelve Swift Concurrency los data races y cuáles son sus limitaciones?
&lt;/h2&gt;

&lt;p&gt;Para evitar un data race se puede restringir el acceso a los datos por medio de un &lt;code&gt;actor&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;El ejemplo anterior se puede cambiar así:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight swift"&gt;&lt;code&gt;&lt;span class="kd"&gt;actor&lt;/span&gt; &lt;span class="kt"&gt;Counter&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="nv"&gt;value&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;
  &lt;span class="kd"&gt;func&lt;/span&gt; &lt;span class="nf"&gt;increment&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;value&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="kd"&gt;func&lt;/span&gt; &lt;span class="nf"&gt;getValue&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="kt"&gt;Int&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;value&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight swift"&gt;&lt;code&gt;&lt;span class="kd"&gt;nonisolated&lt;/span&gt; &lt;span class="kd"&gt;struct&lt;/span&gt; &lt;span class="kt"&gt;DataRaceDemonstrator&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;

  &lt;span class="kd"&gt;func&lt;/span&gt; &lt;span class="nf"&gt;demonstrate&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="kt"&gt;Int&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;counter&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kt"&gt;Counter&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;_&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="o"&gt;...&lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;counter&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;increment&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;counter&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getValue&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight swift"&gt;&lt;code&gt;&lt;span class="kd"&gt;struct&lt;/span&gt; &lt;span class="kt"&gt;DataRaceDemonstratorTests&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;

  &lt;span class="kd"&gt;@Test&lt;/span&gt;
  &lt;span class="kd"&gt;func&lt;/span&gt; &lt;span class="nf"&gt;exec&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;sut&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kt"&gt;DataRaceDemonstrator&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;sut&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;demonstrate&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="cp"&gt;#expect(result == 10)&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Para acceder a los datos del dominio de aislamiento del &lt;code&gt;actor&lt;/code&gt; &lt;code&gt;Counter&lt;/code&gt; desde cualquier otro dominio de aislamiento, sí o sí se debe usar &lt;code&gt;await&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  6. ¿Por qué los data races son difíciles de detectar y reproducir?
&lt;/h2&gt;

&lt;p&gt;Es muy difícil detectar una carrera de datos porque:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Determinar que hace falta sincronización es difícil. Depende de la experiencia del desarrollador.&lt;/li&gt;
&lt;li&gt;El código inseguro no necesariamente falla en producción.&lt;/li&gt;
&lt;li&gt;Las fallas en runtime son difíciles de reproducir.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  7. ¿Qué ventaja ofrece un actor sobre una serial queue de GCD?
&lt;/h2&gt;

&lt;p&gt;Al usar la cola serial de GCD, igual hay que recordar leer y modificar los datos con &lt;code&gt;serialQueue.async&lt;/code&gt;, mientras que el &lt;code&gt;actor&lt;/code&gt; te obliga a usar &lt;code&gt;await&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  8. Según el artículo, ¿por qué el primer ejemplo de código con &lt;code&gt;DispatchQueue.global&lt;/code&gt; es problemático aunque parezca correcto?
&lt;/h2&gt;

&lt;p&gt;La operación &lt;code&gt;counter += 1&lt;/code&gt; no es atómica: Implica leer el valor, sumarle uno y escribirlo de nuevo. Como se usa una cola concurrente, entonces múltiples hilos podrían estar ejecutando la operación simultáneamente. Si un hilo está leyendo un valor antes de que otro haya terminado de escribir, se puede corromper el sistema.&lt;/p&gt;

&lt;p&gt;Lo más peligroso es que el código no garantiza fallar en tiempo de ejecución, lo que lo hace muy difícil de detectar y reproducir.&lt;/p&gt;

&lt;h2&gt;
  
  
  9. ¿Por qué la versión con &lt;code&gt;Task&lt;/code&gt; dentro del bucle sigue teniendo problemas a pesar de usar un &lt;code&gt;actor&lt;/code&gt;?
&lt;/h2&gt;

&lt;p&gt;El actor resuelve el problema de quieen accede al dato, pero no controla cuándo terminan las tareas. Cada &lt;code&gt;Task&lt;/code&gt; se lanza de forma independiente y asíncrona. Cuando se ejecuta la línea final &lt;code&gt;counter.getValue()&lt;/code&gt; no hay ninguna garantía de que las 10 tareas hayan completado sus incrementos.&lt;/p&gt;

&lt;p&gt;El actor cumple su función (no hay dos escrituras simultáneas) pero el orden y la finalización de las tareas queda indefinido.&lt;/p&gt;

&lt;h2&gt;
  
  
  Recite
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;¿Puedes explicar con tus propias palabras la diferencia entre un data race y una race condition?&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;"data race" es un problema de sincronización de hilos a la hora de acceder a una región de memoria, donde al menos uno está modificándola.&lt;/p&gt;

&lt;p&gt;Un "race condition" es un problema que aparece cuando el resultado del programa depende del orden de ejecución de las tareas, y este no puede garantizarse.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;¿Qué garantiza el uso de &lt;code&gt;await&lt;/code&gt; al acceder a propiedades de un &lt;code&gt;actor&lt;/code&gt;?&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Usar &lt;code&gt;await&lt;/code&gt; en &lt;code&gt;actor&lt;/code&gt; garantiza sincronización en el accedo a un dato. Esto resuelve el problema de "data race", pero no "race condition".&lt;/p&gt;

&lt;h2&gt;
  
  
  Review
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;¿Swift Concurrency resuelve completamente los problemas de concurrencia? ¿Por qué sí o por qué no?&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Resuelve el problema de "data race", pero no "race condition".&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;¿Qué es el protocolo &lt;code&gt;Sendable&lt;/code&gt; y cuál es su relación con los conceptos explicados en el artículo?&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;code&gt;Sendable&lt;/code&gt; es un tipo de dato que garantiza acceso seguro a su estado. Al usarlo se le dice al compilador que es seguro acceder a estos valores desde cualquier dominio de aislamiento.&lt;/p&gt;




&lt;h2&gt;
  
  
  Bibliografía
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://courses.avanderlee.com/p/swift-concurrency" rel="noopener noreferrer"&gt;Van der Lee, A. (2025). &lt;em&gt;Swift Concurrency Course&lt;/em&gt; [Curso en línea]. avanderlee.com.&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>swift</category>
      <category>ios</category>
      <category>concurrency</category>
    </item>
    <item>
      <title>[SC] Sendable</title>
      <dc:creator>GoyesDev</dc:creator>
      <pubDate>Mon, 16 Mar 2026 20:42:16 +0000</pubDate>
      <link>https://dev.to/david_goyes_a488f58a17a53/sc-sendable-4k3j</link>
      <guid>https://dev.to/david_goyes_a488f58a17a53/sc-sendable-4k3j</guid>
      <description>&lt;h2&gt;
  
  
  ¿Qué diferencia hay entre pasar valores entre hilos en GCD versus en Swift Concurrency?
&lt;/h2&gt;

&lt;p&gt;Igual que en GCD, en Swift Concurrency (SC) va a ser necesario pasar un dato de un hilo a otro. Sin embargo, en SC no se trabaja con hilos sino con "Dominios de Aislamiento" (del inglés "isolation domains").&lt;/p&gt;

&lt;p&gt;Al pasar un dato de una función &lt;code&gt;async&lt;/code&gt; a otra, se podría estar transfiriendo información entre dos dominios de aislamiento, para lo cual, SC necesita que el dato sea de tipo &lt;a href="https://developer.apple.com/documentation/Swift/Sendable" rel="noopener noreferrer"&gt;&lt;code&gt;Sendable&lt;/code&gt;&lt;/a&gt; para garantizar que sea "thread-safe".&lt;/p&gt;

&lt;h2&gt;
  
  
  ¿Por qué el compilador necesita saber si un valor es thread-safe?
&lt;/h2&gt;

&lt;h2&gt;
  
  
  ¿Qué es un isolation domain y para qué sirve?
&lt;/h2&gt;

&lt;p&gt;Un &lt;em&gt;Dominio de Aislamiento&lt;/em&gt; ("Isolation Domain") define una frontera en la que se puede acceder a un valor o referencia sin el riesgo de tener una carrera de datos.&lt;/p&gt;

&lt;p&gt;Hay tres tipos de dominio:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;nonisolated&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;actor&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Global-actor.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  ¿Qué restricciones tiene el código &lt;code&gt;nonisolated&lt;/code&gt; respecto al estado de otros dominios?
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;nonisolated&lt;/code&gt; es el "Dominio de Aislamiento" por defecto que no tiene restricciones de concurrencia. El código &lt;code&gt;nonisolated&lt;/code&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Puede modificar sin problema el estado de otro código del mismo tipo.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;NO&lt;/strong&gt; puede modificar el estado de otros Dominios de Aislamiento.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;El siguiente método no tiene estado y por eso se puede llamar con seguridad desde cualquier hilo:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight swift"&gt;&lt;code&gt;&lt;span class="c1"&gt;// ⚠️ Como nonisolated es el dominio de aislamiento por defecto, es redundante ponerlo.&lt;/span&gt;
&lt;span class="kd"&gt;nonisolated&lt;/span&gt; &lt;span class="kd"&gt;func&lt;/span&gt; &lt;span class="nf"&gt;add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;a&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;Int&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;b&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;Int&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="kt"&gt;Int&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="kd"&gt;func&lt;/span&gt; &lt;span class="nf"&gt;add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;a&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;Int&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;b&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;Int&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="kt"&gt;Int&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  ¿Por qué acceder a propiedades de un actor desde afuera requiere &lt;code&gt;await&lt;/code&gt;?
&lt;/h2&gt;

&lt;p&gt;Un &lt;code&gt;actor&lt;/code&gt; es un dominio de aislamiento que asegura que todas sus propiedades almacenadas y métodos se ejecutan en un ambiente seguro de un solo hilo, evitando carreras de datos.&lt;/p&gt;

&lt;p&gt;Para acceder a los datos almacenados en un &lt;code&gt;actor&lt;/code&gt;, se debe usar &lt;code&gt;await&lt;/code&gt; para garantizar el acceso correcto. Básicamente sería como esperar hasta que el actor entregue o termine de modificar los datos.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight swift"&gt;&lt;code&gt;&lt;span class="c1"&gt;// ⚠️ Se define la estructura de datos como "actor"&lt;/span&gt;
&lt;span class="kd"&gt;actor&lt;/span&gt; &lt;span class="kt"&gt;Library&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;

  &lt;span class="c1"&gt;// ⚠️ No se puede acceder directamente a books. Se puede leer&lt;/span&gt;
  &lt;span class="c1"&gt;// usando await, pero no escribir. Es ideal marcarlo private&lt;/span&gt;
  &lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="nv"&gt;books&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="kt"&gt;String&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;

  &lt;span class="c1"&gt;// ⚠️ Notar que los métodos no tienen async. Sin embargo, &lt;/span&gt;
  &lt;span class="c1"&gt;// al estar definidos dentro del actor, están dentro de su&lt;/span&gt;
  &lt;span class="c1"&gt;// dominio de aislamiento y deben ser accedidos con await&lt;/span&gt;
  &lt;span class="c1"&gt;// desde otro dominio.&lt;/span&gt;
  &lt;span class="kd"&gt;func&lt;/span&gt; &lt;span class="nf"&gt;addBook&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;_&lt;/span&gt; &lt;span class="nv"&gt;title&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;String&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;books&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;title&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="kd"&gt;func&lt;/span&gt; &lt;span class="nf"&gt;getBookList&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="kt"&gt;String&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;books&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="c1"&gt;// ⚠️ Un actor también puede tener métodos nonisolated. &lt;/span&gt;
  &lt;span class="c1"&gt;// En este caso, para retornar un String escalar que puede&lt;/span&gt;
  &lt;span class="c1"&gt;// se accedido desde cualquier lado SIN await&lt;/span&gt;
  &lt;span class="kd"&gt;nonisolated&lt;/span&gt; &lt;span class="kd"&gt;func&lt;/span&gt; &lt;span class="nf"&gt;libraryName&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="kt"&gt;String&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="s"&gt;"A library of books"&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight swift"&gt;&lt;code&gt;&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;library&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kt"&gt;Library&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

&lt;span class="c1"&gt;// ⚠️ No se puede invocar un método del actor, fuera de este,&lt;/span&gt;
&lt;span class="c1"&gt;// de forma síncrona.&lt;/span&gt;
&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;addBook&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"hola"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="c1"&gt;// ❌ Call to actor-isolated instance method 'addBook' in a synchronous main actor-isolated context. Calls to instance method 'addBook' from outside of its actor context are implicitly asynchronous&lt;/span&gt;

&lt;span class="kt"&gt;Task&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;library&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;addBook&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Dopamine Nation"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="c1"&gt;// ⚠️ Se debe llamar el método con await&lt;/span&gt;
  &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;books&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;library&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getBookList&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
  &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;books&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="c1"&gt;// Imprime: ["Dopamine Nation"]&lt;/span&gt;

  &lt;span class="c1"&gt;// ⚠️ Se puede leer books con await&lt;/span&gt;
  &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;library&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;books&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;forEach&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="c1"&gt;// Imprime: ["Dopamine Nation"]&lt;/span&gt;

  &lt;span class="c1"&gt;// ⚠️ No se puede escribir books fuera del actor&lt;/span&gt;
  &lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;books&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Dopamine Nation"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="c1"&gt;// ❌ Error en Swift 6: Actor-isolated property 'books' can not be mutated from the main actor. Consider declaring an isolated method on 'Library' to perform the mutation&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  ¿En qué se diferencia un global actor como &lt;code&gt;@MainActor&lt;/code&gt; de un actor regular?
&lt;/h2&gt;

&lt;p&gt;Mientras que un &lt;code&gt;actor&lt;/code&gt; crea un dominio de aislamiento en una sola instancia, un &lt;code&gt;global actor&lt;/code&gt; es un dominio de aislamiento compartido por varios tipos de datos, propiedades y funciones. Esto es útil cuando varias partes de la aplicación necesitan funcionar bajo las mismas restricciones.&lt;/p&gt;

&lt;h2&gt;
  
  
  ¿Qué condiciones debe cumplir una API pública para considerarse thread-safe ("&lt;strong&gt;seguro entre hilos&lt;/strong&gt;") según el protocolo &lt;code&gt;Sendable&lt;/code&gt;?
&lt;/h2&gt;

&lt;p&gt;El protocolo &lt;code&gt;Sendable&lt;/code&gt; indica que cierta interfaz es thread-safe para el compilador. Se considera que una interfaz es &lt;strong&gt;segura para usar entre dominios de aislamiento&lt;/strong&gt; cuando:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;No hay modificadores públicos.&lt;/li&gt;
&lt;li&gt;Cuenta con un sistema de bloqueo interno (e.g. proteger la escritura de un valor con ayuda de &lt;code&gt;NSLock&lt;/code&gt;).&lt;/li&gt;
&lt;li&gt;Los modificadores implementan copy-on-write como los tipos de valor.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Muchos tipos de datos de la biblioteca estándar de Swift ya tienen soporte del protocolo &lt;code&gt;Sendable&lt;/code&gt;. Luego, el compilador puede hacer que algunos tipos de datos también tengan soporte automático de &lt;code&gt;Sendable&lt;/code&gt;:&lt;/p&gt;

&lt;p&gt;Por ejemplo, dado que &lt;code&gt;Int: Sendable&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight swift"&gt;&lt;code&gt;&lt;span class="c1"&gt;// ✅ SomeStruct conforma implícitamente Sendable&lt;/span&gt;
&lt;span class="kd"&gt;struct&lt;/span&gt; &lt;span class="kt"&gt;SomeStruct&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="nv"&gt;someIntValue&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;Int&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight swift"&gt;&lt;code&gt;&lt;span class="c1"&gt;// ❌ SomeClass NO conforma implícitamente Sendable&lt;/span&gt;
&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="kt"&gt;SomeClass&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="nv"&gt;someIntValue&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;Int&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Recite
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;¿Por qué un &lt;code&gt;struct&lt;/code&gt; con una propiedad &lt;code&gt;Int&lt;/code&gt; conforma &lt;code&gt;Sendable&lt;/code&gt; implícitamente, pero una &lt;code&gt;class&lt;/code&gt; con la misma propiedad no?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Porque &lt;code&gt;class&lt;/code&gt; es un tipo por referencia, lo que implica que puede ser modificado desde dos dominios de aislamiento diferentes.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;¿Puedes explicar con tus propias palabras qué ocurre cuando un valor viaja entre dos dominios de aislamiento?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Swift debe garantizar que el valor puede trasladarse desde un dominio a otro sin el riesgo de una carrera de datos.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;¿Cuándo tendría sentido marcar un método como &lt;code&gt;nonisolated&lt;/code&gt; dentro de un actor?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Se puede marcar con &lt;code&gt;nonisolated&lt;/code&gt; si no es necesario proteger el estado del actor. Esto ocurre, por ejemplo, si el método retorna algún valor escalar o constante.&lt;/p&gt;




&lt;h2&gt;
  
  
  Review
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;¿Cuáles son las tres condiciones bajo las cuales una API pública es segura para usarse entre dominios de concurrencia?&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;¿Qué cambia en Swift 6.2 respecto al comportamiento por defecto de &lt;code&gt;Sendable&lt;/code&gt;?&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Se introduce &lt;code&gt;nonisolated(nonsending)&lt;/code&gt; que permite que las funciones y closures no sean &lt;code&gt;Sendable&lt;/code&gt; a no ser de que atraviesen una frontera de aislamiento.&lt;/p&gt;




&lt;h2&gt;
  
  
  Bibliografía
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://courses.avanderlee.com/p/swift-concurrency" rel="noopener noreferrer"&gt;Van der Lee, A. (2025). &lt;em&gt;Swift Concurrency Course&lt;/em&gt; [Curso en línea]. avanderlee.com.&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>swift</category>
      <category>ios</category>
      <category>concurrency</category>
      <category>swiftconcurrency</category>
    </item>
  </channel>
</rss>
