<?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] nonisolated(nonsending) y @concurrent</title>
      <dc:creator>GoyesDev</dc:creator>
      <pubDate>Tue, 28 Apr 2026 22:10:03 +0000</pubDate>
      <link>https://dev.to/david_goyes_a488f58a17a53/sc-nonisolatednonsending-y-concurrent-91k</link>
      <guid>https://dev.to/david_goyes_a488f58a17a53/sc-nonisolatednonsending-y-concurrent-91k</guid>
      <description>&lt;h2&gt;
  
  
  Preguntas
&lt;/h2&gt;

&lt;h3&gt;
  
  
  ¿Cuál es la diferencia entre el comportamiento anterior y el nuevo de las funciones &lt;code&gt;nonisolated async&lt;/code&gt; a partir de Swift 6.2?
&lt;/h3&gt;

&lt;p&gt;Antes de Swift 6.2, las funciones &lt;code&gt;nonisolated async&lt;/code&gt; se ejecutaban de forma independiente, &lt;strong&gt;sin heredar el contexto de ejecución&lt;/strong&gt;. Esto significa que cada función &lt;code&gt;nonisolated async&lt;/code&gt; es una sub-tarea que decide por sí misma dónde ejecutarse. Si se anota con &lt;code&gt;@MainActor&lt;/code&gt; o algún &lt;code&gt;@globalActor&lt;/code&gt;, entonces se va a ejecutar en el &lt;code&gt;executor&lt;/code&gt; de dicho actor. En caso contrario, se va a ir a un hilo de segundo plano.&lt;/p&gt;

&lt;p&gt;A partir de Swift 6.2 las funciones &lt;code&gt;nonisolated async&lt;/code&gt; corren, por defecto, en al actor invocador.&lt;/p&gt;

&lt;p&gt;Para rechazar la herencia de dominio de aislamiento, se debe marcar el método específicamente con el atributo &lt;code&gt;@concurrent&lt;/code&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  ¿Bajo qué circunstancias una tarea (&lt;code&gt;Task&lt;/code&gt;) puede ejecutarse en el hilo principal en lugar de en un hilo en segundo plano?
&lt;/h3&gt;

&lt;p&gt;Una &lt;code&gt;Task&lt;/code&gt; se puede ejecutar en el hilo principal si está marcada con &lt;code&gt;@MainActor&lt;/code&gt;, o si fue invocada por una tarea marcada con &lt;code&gt;@MainActor&lt;/code&gt; en Swift 6.2.&lt;/p&gt;

&lt;h3&gt;
  
  
  ¿Para qué sirve el atributo &lt;code&gt;@concurrent&lt;/code&gt; y cuándo se debe usar?
&lt;/h3&gt;

&lt;p&gt;&lt;code&gt;@concurrent&lt;/code&gt; sirve para que un método &lt;code&gt;nonisolated async&lt;/code&gt; &lt;strong&gt;NO&lt;/strong&gt; herede el contexto del método invocador.&lt;/p&gt;

&lt;h3&gt;
  
  
  ¿Qué problema resuelve &lt;code&gt;nonisolated(nonsending)&lt;/code&gt; y cuándo es apropiado aplicarlo?
&lt;/h3&gt;

&lt;p&gt;En caso de que la propiedad &lt;code&gt;NonisolatedNonsendingByDefault&lt;/code&gt; esté puesta en &lt;code&gt;NO&lt;/code&gt;, puede aparecer un error como &lt;code&gt;Sending value of non-Sendable type ‘MyType’ risks causing data races&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Este error aparece porque Swift asume que, sin &lt;code&gt;nonisolated(nonsending), la función va a correr en un dominio de aislamiento diferente al del llamador. Cuando eso pasa, Swift necesita enviar el valor (&lt;/code&gt;self&lt;code&gt;u otros parámetros) de un dominio a otro - y si el tipo no es&lt;/code&gt;Sendable`, el compilador dice: "Peligro, datarace!".&lt;/p&gt;

&lt;p&gt;&lt;code&gt;nonisolated(nonsending)&lt;/code&gt; le dice al compilador: "Esta función va a heredar el dominio de aislamiento del llamador, así que no hay ningún envío entre dominios".&lt;/p&gt;

&lt;p&gt;Si no hay envío, no hay riesgo de data race.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;nonisolated(nonsending)&lt;/code&gt; no es una solución mágica universal. Funciona solo cuando de verdad estoy de acuerdo con que la función bloquee el actor del llamador.&lt;/p&gt;

&lt;p&gt;Si la función hace algo pesado, usar &lt;code&gt;nonisolated(nonsending)&lt;/code&gt; podría bloquear el hilo en cuestión. En ese caso, la solución correcta sería hacer el tipo &lt;code&gt;Sendable&lt;/code&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  ¿Cómo se puede verificar en qué hilo se está ejecutando una tarea durante el desarrollo?
&lt;/h3&gt;

&lt;p&gt;Usar &lt;code&gt;Thread.current&lt;/code&gt;. Teniendo en cuenta que posiblemente sea necesario usar la extensión:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;&lt;/code&gt;&lt;code&gt;swift&lt;br&gt;
extension Thread {&lt;br&gt;
  public static var currentThread: Thread {&lt;br&gt;
    return Thread.current&lt;br&gt;
  }&lt;br&gt;
}&lt;br&gt;
&lt;/code&gt;&lt;code&gt;&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Por otro lado, siempre se puede poner un punto de quiebre para mirar en qué hilo se está parado.&lt;/p&gt;

&lt;h3&gt;
  
  
  ¿cómo explica el autor que el actor de llamada puede influir en el hilo donde se ejecuta una tarea?
&lt;/h3&gt;

&lt;p&gt;El actor del llamador determina dónde empieza la tarea y a dónde regresa después de cada punto de suspensión.&lt;/p&gt;

&lt;p&gt;En el ejemplo del artículo:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;&lt;/code&gt;`swift&lt;br&gt;
@MainActor&lt;br&gt;
private func updateUI() {&lt;br&gt;
  Task {&lt;br&gt;
    print("Starting on the main thread")&lt;br&gt;
    await someBackgroundTask()&lt;br&gt;
    print("Resuming on the main thread")&lt;br&gt;
  }&lt;br&gt;
}&lt;/p&gt;

&lt;p&gt;private func someBackgroundTask() async {&lt;br&gt;
    print("Background task on thread: 8")&lt;br&gt;
}&lt;br&gt;
`&lt;code&gt;&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;code&gt;someBackgroundTask()&lt;/code&gt; corre en el hilo 8. No obstante, la primera línea del &lt;code&gt;Task&lt;/code&gt; de &lt;code&gt;updateUI() corre en el hilo 1, y después de la suspensión de &lt;/code&gt;await someBackgroundTask()`, el trabajo regresa al hilo 1.&lt;/p&gt;

&lt;h3&gt;
  
  
  ¿Qué cambio introduce SE-461 y cuál es la justificación filosófica que da el autor al citarlo?
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://github.com/swiftlang/swift-evolution/blob/main/proposals/0461-async-function-isolation.md" rel="noopener noreferrer"&gt;SE-461: Run nonisolated async functions on the caller’s actor by default&lt;/a&gt; hace que las funciones &lt;code&gt;nonisolated async&lt;/code&gt; hereden el contexto del método invocador. En caso de no querer que esto pase, entonces hay que marcar con el atributo &lt;code&gt;@concurrent&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;El comportamiento anterior de las funciones &lt;code&gt;nonisolated async&lt;/code&gt; sacrificaba usabilidad innecesariamente para proteger la responsividad del hilo principal.&lt;/p&gt;




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

&lt;h3&gt;
  
  
  ¿puedes explicar con tus palabras qué ocurre cuando una función nonisolated es llamada desde un contexto &lt;code&gt;@MainActor&lt;/code&gt; en Swift 6.2 con el nuevo flag activado?
&lt;/h3&gt;

&lt;h3&gt;
  
  
  ¿Cuándo elegirías &lt;code&gt;@concurrent&lt;/code&gt; y cuándo &lt;code&gt;nonisolated(nonsending)&lt;/code&gt;? ¿Puedes describir un caso de uso para cada uno?
&lt;/h3&gt;

&lt;h3&gt;
  
  
  ¿Cómo habilitarías el nuevo comportamiento de &lt;code&gt;NonisolatedNonsendingByDefault&lt;/code&gt; en un proyecto de Xcode?
&lt;/h3&gt;




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

&lt;h3&gt;
  
  
  ¿Cómo se relacionan los conceptos de actor isolation, &lt;code&gt;@MainActor&lt;/code&gt; y el pool cooperativo de hilos de Swift?
&lt;/h3&gt;

&lt;h3&gt;
  
  
  ¿Por qué el autor advierte que este cambio puede confundir a quienes ya conocían Swift Concurrency antes de la versión 6.2?
&lt;/h3&gt;

&lt;h3&gt;
  
  
  ¿Qué implicaciones de rendimiento puede tener el nuevo comportamiento por defecto si no se usa &lt;code&gt;@concurrent&lt;/code&gt; donde corresponde?
&lt;/h3&gt;

&lt;h3&gt;
  
  
  ¿En qué se diferencia el error de compilación "Sending value of non-Sendable type" del problema que resuelve &lt;code&gt;nonisolated(nonsending)&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] Puntos de suspensión de una Task</title>
      <dc:creator>GoyesDev</dc:creator>
      <pubDate>Tue, 28 Apr 2026 16:33:05 +0000</pubDate>
      <link>https://dev.to/david_goyes_a488f58a17a53/sc-puntos-de-suspension-de-una-task-4hjk</link>
      <guid>https://dev.to/david_goyes_a488f58a17a53/sc-puntos-de-suspension-de-una-task-4hjk</guid>
      <description>&lt;h2&gt;
  
  
  Preguntas
&lt;/h2&gt;

&lt;h3&gt;
  
  
  ¿Qué es exactamente un punto de suspensión en una tarea de Swift?
&lt;/h3&gt;

&lt;p&gt;Un punto de suspensión es un momento donde una &lt;code&gt;Task&lt;/code&gt; puede pausar su ejecución para permitir que otro trabajo pueda ejecutarse.&lt;/p&gt;

&lt;p&gt;Cada uso de &lt;code&gt;await&lt;/code&gt; es un punto de suspensión potencial.&lt;/p&gt;

&lt;h3&gt;
  
  
  ¿Por qué no todo &lt;code&gt;await&lt;/code&gt; garantiza una suspensión real?
&lt;/h3&gt;

&lt;p&gt;Si la tarea esperada (&lt;code&gt;await&lt;/code&gt;) puede ser completada de forma síncrona, la tarea de origen no se suspende sino que seguirá ejecutando inmediatamente. Esto puede ocurrir cuando el método asíncrono pertenece al mismo dominio de aislamiento. &lt;code&gt;await&lt;/code&gt; simplemente marca un posible punto de suspensión, no uno garantizado.&lt;/p&gt;

&lt;h3&gt;
  
  
  ¿Qué es la reentrada de actores y cuándo ocurre?
&lt;/h3&gt;

&lt;p&gt;Un &lt;code&gt;actor&lt;/code&gt; garantiza que solo una &lt;code&gt;Task&lt;/code&gt; puede acceder a su estado aislado a la vez. Sin embargo, si una tarea encuentra un punto de suspensión dentro del actor, existe la posibilidad de que otra tarea empiece a trabajar con el actor antes de que la primera termine.&lt;/p&gt;

&lt;h3&gt;
  
  
  ¿Qué riesgos concretos introduce un punto de suspensión dentro de un actor?
&lt;/h3&gt;

&lt;p&gt;Todo estado mutable que asume una ejecución ininterrumpida podría comportarse de forma incorrecta si la tarea es suspendida. Esto puede derivar en un estado inconsistente porque podría solaparse con otra tarea que podría mutar el estado del actor antes de que la primera termine.&lt;/p&gt;

&lt;h3&gt;
  
  
  ¿Cómo se puede evitar el comportamiento inesperado por reentrada?
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Evitar modificar el estado mutable de un actor después de un punto de suspensión.&lt;/li&gt;
&lt;li&gt;Guardar información importante para el desarrollo del método en variables locales.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  ¿Qué cambia exactamente en la versión corregida del método &lt;code&gt;deposit&lt;/code&gt;?
&lt;/h3&gt;

&lt;p&gt;El punto de suspensión aparece después de modificar el estado del actor. Todas las modificaciones al estado del actor se agrupan antes del &lt;code&gt;await&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;// Antes&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="k"&gt;async&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="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"[&lt;/span&gt;&lt;span class="se"&gt;\(&lt;/span&gt;&lt;span class="n"&gt;balance&lt;/span&gt;&lt;span class="se"&gt;)&lt;/span&gt;&lt;span class="s"&gt;] Deposited &lt;/span&gt;&lt;span class="se"&gt;\(&lt;/span&gt;&lt;span class="n"&gt;amount&lt;/span&gt;&lt;span class="se"&gt;)&lt;/span&gt;&lt;span class="s"&gt;, balance is now &lt;/span&gt;&lt;span class="se"&gt;\(&lt;/span&gt;&lt;span class="n"&gt;balance&lt;/span&gt;&lt;span class="se"&gt;)&lt;/span&gt;&lt;span class="s"&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;logTransaction&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;amount&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c1"&gt;// ⚠️ Suspension point&lt;/span&gt;

  &lt;span class="n"&gt;balance&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt; &lt;span class="c1"&gt;// bonus after logging&lt;/span&gt;
  &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"[&lt;/span&gt;&lt;span class="se"&gt;\(&lt;/span&gt;&lt;span class="n"&gt;balance&lt;/span&gt;&lt;span class="se"&gt;)&lt;/span&gt;&lt;span class="s"&gt;] Applied bonus, balance is now &lt;/span&gt;&lt;span class="se"&gt;\(&lt;/span&gt;&lt;span class="n"&gt;balance&lt;/span&gt;&lt;span class="se"&gt;)&lt;/span&gt;&lt;span class="s"&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="c1"&gt;// Después&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="k"&gt;async&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="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"[&lt;/span&gt;&lt;span class="se"&gt;\(&lt;/span&gt;&lt;span class="n"&gt;balance&lt;/span&gt;&lt;span class="se"&gt;)&lt;/span&gt;&lt;span class="s"&gt;] Deposited &lt;/span&gt;&lt;span class="se"&gt;\(&lt;/span&gt;&lt;span class="n"&gt;amount&lt;/span&gt;&lt;span class="se"&gt;)&lt;/span&gt;&lt;span class="s"&gt;, balance is now &lt;/span&gt;&lt;span class="se"&gt;\(&lt;/span&gt;&lt;span class="n"&gt;balance&lt;/span&gt;&lt;span class="se"&gt;)&lt;/span&gt;&lt;span class="s"&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="mi"&gt;10&lt;/span&gt; &lt;span class="c1"&gt;// bonus after logging&lt;/span&gt;
  &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"[&lt;/span&gt;&lt;span class="se"&gt;\(&lt;/span&gt;&lt;span class="n"&gt;balance&lt;/span&gt;&lt;span class="se"&gt;)&lt;/span&gt;&lt;span class="s"&gt;] Applied bonus, balance is now &lt;/span&gt;&lt;span class="se"&gt;\(&lt;/span&gt;&lt;span class="n"&gt;balance&lt;/span&gt;&lt;span class="se"&gt;)&lt;/span&gt;&lt;span class="s"&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;logTransaction&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;amount&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c1"&gt;// ⚠️ Suspension point&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 / comprensión
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Explica con tus propias palabras por qué el balance pasa de 100 → 200 en lugar de 100 → 110.
&lt;/h3&gt;

&lt;h3&gt;
  
  
  ¿Cuál es la diferencia entre un punto de suspensión posible y uno garantizado?
&lt;/h3&gt;

&lt;h3&gt;
  
  
  ¿Por qué mover el &lt;code&gt;await&lt;/code&gt; al final del método soluciona el problema de reentrada?
&lt;/h3&gt;




&lt;h2&gt;
  
  
  Revisión y síntesis
&lt;/h2&gt;

&lt;h3&gt;
  
  
  ¿Cuál es la regla práctica más importante para mutar el estado de un actor de forma segura?
&lt;/h3&gt;

&lt;h3&gt;
  
  
  ¿En qué situaciones de tu propio código deberías revisar dónde caen los puntos de suspensión?
&lt;/h3&gt;

&lt;h3&gt;
  
  
  ¿Qué tema cubre la siguiente lección y cómo se relaciona con lo aprendido aquí?
&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] Deshacerse de la mentalidad de hilos</title>
      <dc:creator>GoyesDev</dc:creator>
      <pubDate>Tue, 28 Apr 2026 15:36:04 +0000</pubDate>
      <link>https://dev.to/david_goyes_a488f58a17a53/sc-deshacerse-de-la-mentalidad-de-hilos-2bod</link>
      <guid>https://dev.to/david_goyes_a488f58a17a53/sc-deshacerse-de-la-mentalidad-de-hilos-2bod</guid>
      <description>&lt;h2&gt;
  
  
  Preguntas
&lt;/h2&gt;

&lt;h3&gt;
  
  
  ¿Por qué Swift Concurrency quiere que dejes de controlar manualmente los hilos?
&lt;/h3&gt;

&lt;p&gt;Controlar manualmente los hilos trae los siguientes costos:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Costo elevado en memoria (stack de cada thread)&lt;/li&gt;
&lt;li&gt;Intercambio de contextos innecesariamente alto (más trabajo para los procesadores)&lt;/li&gt;
&lt;li&gt;problemas de inversión de prioridad.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Debido a los problemas anteriores, Swift Concurrency nos invita a dejar que el framework se encargue del manejo de hilos.&lt;/p&gt;

&lt;h3&gt;
  
  
  ¿Qué es un dominio de aislamiento y cómo reemplaza el concepto de hilo?
&lt;/h3&gt;

&lt;p&gt;Un dominio de aislamiento es una región o contexto al que pertenece un fragmento de código. Este contexto determina cómo ejecutar el código de forma segura y sin carreras de datos.&lt;/p&gt;

&lt;p&gt;El cambio de paradigma consiste en que ahora se declara a qué dominio pertenece el código y Swift se encarga de ejecutarlo de forma segura, en el hilo que considere más eficiente.&lt;/p&gt;

&lt;h3&gt;
  
  
  ¿Qué papel juegan los actores (&lt;code&gt;actors&lt;/code&gt;) en Swift Concurrency?
&lt;/h3&gt;

&lt;p&gt;Todo el código definido dentro un &lt;code&gt;actor&lt;/code&gt; pertenece a su dominio de aislamiento y es ejecutado por un &lt;code&gt;executor&lt;/code&gt; independiente, lo que garantiza que el código se ejecute de forma serial dentro del actor, evitando acceso concurrentes a su estado interno.&lt;/p&gt;

&lt;h3&gt;
  
  
  ¿Cómo se le dan "pistas" al sistema sobre la prioridad de una tarea?
&lt;/h3&gt;

&lt;p&gt;La "prioridad" de una tarea no establece directamente el orden de ejecución del código, sino que sugiere al runtime el nivel de importancia que tiene el bloque a ejecutar.&lt;/p&gt;

&lt;p&gt;Sin embargo, puede darse el caso que tenga una tarea de prioridad alta que esté esperando a que una tarea de prioridad baja termine. Por esto se dice que la "prioridad" de una tarea es más bien una sugerencia.&lt;/p&gt;

&lt;h3&gt;
  
  
  ¿Por qué una tarea de alta prioridad no garantiza ejecución inmediata?
&lt;/h3&gt;

&lt;p&gt;La prioridad de una "tarea" es una sugerencia para el runtime. No se está asignando la tarea a un hilo, sino que se está indicando la naturaleza del trabajo a realizar.&lt;/p&gt;

&lt;h3&gt;
  
  
  ¿Qué problema resuelve la conformancia con &lt;code&gt;Sendable&lt;/code&gt;?
&lt;/h3&gt;

&lt;p&gt;Un dato &lt;code&gt;Sendable&lt;/code&gt; es seguro para cruzar dominios de aislamiento. Como Swift puede mover código entre hilos y no se puede predecir en cuál reanudará, es necesario garantizar que los datos compartidos entre dominios son seguros de transferir.&lt;/p&gt;

&lt;h3&gt;
  
  
  Según el artículo, ¿cuáles son los tres problemas que evita dejar que Swift gestione los hilos?
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Uso excesivo de memoria (para guardar el contexto)&lt;/li&gt;
&lt;li&gt;Uso elevado de procesador (para cambiar de contexto)&lt;/li&gt;
&lt;li&gt;Inversión de prioridad&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  En el ejemplo de código, ¿por qué la "&lt;code&gt;Task&lt;/code&gt; 1" aparece ejecutándose en hilos distintos al inicio y al reanudarse?
&lt;/h3&gt;

&lt;p&gt;La creación de una &lt;code&gt;Task&lt;/code&gt; no garantiza la ejecución en un hilo específico. En el ejemplo, ante la aparición del punto de suspensión, la &lt;code&gt;Task&lt;/code&gt; 1 cambió de hilo.&lt;/p&gt;




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

&lt;h3&gt;
  
  
  Con tus propias palabras, ¿qué significa pensar en dominios de aislamiento en lugar de hilos?
&lt;/h3&gt;

&lt;h3&gt;
  
  
  Explica por qué Sendable se vuelve necesario precisamente porque Swift puede mover trabajo entre hilos.
&lt;/h3&gt;




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

&lt;h3&gt;
  
  
  ¿Qué cambio mental fundamental propone el artículo respecto a cómo escribir código concurrente en Swift?
&lt;/h3&gt;

&lt;h3&gt;
  
  
  ¿Cómo conectan entre sí los conceptos de actores, prioridades y Sendable dentro del modelo de Swift Concurrency?
&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] Relación entre Hilos y Tasks</title>
      <dc:creator>GoyesDev</dc:creator>
      <pubDate>Tue, 28 Apr 2026 11:47:54 +0000</pubDate>
      <link>https://dev.to/david_goyes_a488f58a17a53/sc-relacion-entre-hilos-y-tasks-3n2m</link>
      <guid>https://dev.to/david_goyes_a488f58a17a53/sc-relacion-entre-hilos-y-tasks-3n2m</guid>
      <description>&lt;h2&gt;
  
  
  Preguntas
&lt;/h2&gt;

&lt;h3&gt;
  
  
  ¿Qué es exactamente un hilo y por qué tiene un alto costo de creación y cambio de contexto?
&lt;/h3&gt;

&lt;p&gt;Un hilo es un recurso, manejado por el sistema operativo, que ejecuta una secuencia de instrucciones. Crear hilos y cambiar el contexto entre ellos es una operación muy costosa.&lt;/p&gt;

&lt;p&gt;Cada hilo requiere su propia pila de memoria (stack) y el cambio de contexto obliga al CPU a guardar y restaurar el estado completo del hilo (registros, puntero de instrucción, etc).&lt;/p&gt;

&lt;h3&gt;
  
  
  ¿Por qué Swift Concurrency no garantiza en qué hilo se ejecutará una función asíncrona?
&lt;/h3&gt;

&lt;p&gt;Swift Concurrency dispone de un pool global concurrente de hilos (tantos como el número de procesadores del dispositivo).&lt;/p&gt;

&lt;p&gt;Para optimizar el uso de hilos, se despacha una &lt;code&gt;Task&lt;/code&gt; en cualquier hilo disponible. Cuando hay un punto de suspensión (&lt;code&gt;await&lt;/code&gt;), el runtime de Swift Concurrency cede el hilo a cualquier otra tarea. Luego, cuando la &lt;code&gt;Task&lt;/code&gt; recupera el contexto, el runtime de SC le asigna cualquier hilo disponible - que puede ser el que tenía inicialmente, pero no está garantizado, porque el sistema pudo haberlo asignado a otra &lt;code&gt;Task&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Aquí quien limita los hilos no es el sistema operativo sino el framework Swift Concurrency. El sistema operativo podría crear muchos más hilos (como lo hacía GCD). Es una decisión de diseño del framework, no una restricción del sistema operativo.&lt;/p&gt;

&lt;h3&gt;
  
  
  ¿Qué ocurre exactamente cuando una tarea llega a un punto de suspensión con &lt;code&gt;await&lt;/code&gt;?
&lt;/h3&gt;

&lt;p&gt;El sistema &lt;strong&gt;suspende&lt;/strong&gt; la &lt;code&gt;Task&lt;/code&gt; y devuelve el hilo al pool global de hilos - Lo que significa que está disponible para que cualquier otra &lt;code&gt;Task&lt;/code&gt; lo tome.&lt;/p&gt;

&lt;h3&gt;
  
  
  ¿Cómo funciona el &lt;code&gt;cooperative thread pool&lt;/code&gt; y por qué limita los hilos al número de núcleos de CPU?
&lt;/h3&gt;

&lt;p&gt;Para no tener "thread explosion" y así degradar el desempeño de la aplicación debido al cambio de contexto entre hilos  y posibles problemas de inversión de prioridades, el sistema operativo limita la creación de hilos al número de núcleos del procesador.&lt;/p&gt;

&lt;p&gt;El "cooperative thread pool" son todos los hilos disponibles para ser usados por las distintas &lt;code&gt;Task&lt;/code&gt;s.&lt;/p&gt;

&lt;h3&gt;
  
  
  ¿Qué es el &lt;code&gt;thread explosion&lt;/code&gt; y cómo lo evita Swift Concurrency?
&lt;/h3&gt;

&lt;p&gt;"thread explosion" ocurre porque se crean demasiados hilos y aparecen bloqueos que provocan:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Desperdicio de memoria debido a los hilos detenidos.&lt;/li&gt;
&lt;li&gt;Intercambio excesivo de contexto (que reduce la eficiencia del procesador)&lt;/li&gt;
&lt;li&gt;Problemas de inversión de prioridad.&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  ¿Por qué tener menos hilos no reduce el rendimiento comparado con GCD?
&lt;/h3&gt;

&lt;p&gt;Aunque es contraintuitivo, el intercambio innecesario de contexto y el desperdicio de memoria son problemas que se reducen al tener menos hilos.&lt;/p&gt;

&lt;h3&gt;
  
  
  ¿Qué demuestra el ejemplo de código con &lt;code&gt;ThreadingDemonstrator&lt;/code&gt; sobre la relación entre tareas e hilos?
&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;private&lt;/span&gt; &lt;span class="kd"&gt;struct&lt;/span&gt; &lt;span class="kt"&gt;ThreadingDemonstrator&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="kd"&gt;func&lt;/span&gt; &lt;span class="nf"&gt;firstTask&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="k"&gt;throws&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="s"&gt;"Task 1 started on thread: &lt;/span&gt;&lt;span class="se"&gt;\(&lt;/span&gt;&lt;span class="kt"&gt;Thread&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;currentThread&lt;/span&gt;&lt;span class="se"&gt;)&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="kt"&gt;Task&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;sleep&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;for&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;seconds&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="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Task 1 resumed on thread: &lt;/span&gt;&lt;span class="se"&gt;\(&lt;/span&gt;&lt;span class="kt"&gt;Thread&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;currentThread&lt;/span&gt;&lt;span class="se"&gt;)&lt;/span&gt;&lt;span class="s"&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;private&lt;/span&gt; &lt;span class="kd"&gt;func&lt;/span&gt; &lt;span class="nf"&gt;secondTask&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="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Task 2 started on thread: &lt;/span&gt;&lt;span class="se"&gt;\(&lt;/span&gt;&lt;span class="kt"&gt;Thread&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;currentThread&lt;/span&gt;&lt;span class="se"&gt;)&lt;/span&gt;&lt;span class="s"&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;demonstrate&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="k"&gt;try&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;firstTask&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="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;secondTask&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="kd"&gt;struct&lt;/span&gt; &lt;span class="kt"&gt;ThreadingDemonstratorTests&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="k"&gt;async&lt;/span&gt; &lt;span class="k"&gt;throws&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;ThreadingDemonstrator&lt;/span&gt;&lt;span class="p"&gt;()&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="k"&gt;try&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="kt"&gt;Task&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;sleep&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;for&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;seconds&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="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;No se puede garantizar el orden de ejecución de las tareas &lt;code&gt;firstTask&lt;/code&gt; y &lt;code&gt;secondTask&lt;/code&gt;. Para hacerlo hay que usar &lt;code&gt;await&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Cuando se asigna un hilo a una tarea y esta se suspende, no se puede garantizar que lo recupere una vez se reanude.&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  ¿Por qué la tarea 1 puede reanudarse en un hilo diferente al que inició?
&lt;/h3&gt;

&lt;p&gt;Cuando se suspende la tarea 1, cede ("yield") el hilo que tenía y el sistema operativo es libre de asignárselo a cualquier otra tarea.&lt;/p&gt;

&lt;h3&gt;
  
  
  ¿Qué diferencia introduce el modo Swift 6 respecto a acceder a &lt;code&gt;Thread.current&lt;/code&gt; y cómo se resuelve?
&lt;/h3&gt;

&lt;p&gt;Usar &lt;code&gt;Thread.current&lt;/code&gt; desde un contexto asíncrono arrojará el error de compilación: &lt;code&gt;Class property 'current' is unavailable from asynchronous contexts; Thread.current cannot be used from async contexts.&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;La solución fue envolver el llamado de &lt;code&gt;Thread.current&lt;/code&gt; en un método (variable computada) &lt;code&gt;nonisolated static&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;extension&lt;/span&gt; &lt;span class="kt"&gt;Thread&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;nonisolated&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;currentThread&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;Thread&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="kt"&gt;Thread&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;current&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 qué significa "ceder el hilo" (yielding the thread) cuando se usa await.
&lt;/h3&gt;

&lt;h3&gt;
  
  
  ¿Cuáles son los tres conceptos erróneos sobre Swift Concurrency que menciona el artículo? ¿Puedes refutarlos?
&lt;/h3&gt;

&lt;h3&gt;
  
  
  ¿Qué tres consecuencias negativas produce el thread explosion en GCD?
&lt;/h3&gt;

&lt;h3&gt;
  
  
  ¿Cómo describirías el cooperative thread pool a alguien sin experiencia en concurrencia?
&lt;/h3&gt;




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

&lt;h3&gt;
  
  
  ¿En qué situaciones concretas deberías seguir pensando en si algo corre en el hilo principal o en un hilo en segundo plano?
&lt;/h3&gt;

&lt;h3&gt;
  
  
  Si Swift Concurrency ya gestiona los hilos automáticamente, ¿qué valor tiene entender cómo funcionan internamente?
&lt;/h3&gt;

&lt;h3&gt;
  
  
  ¿Cómo cambiaría tu forma de escribir código asíncrono ahora que sabes que &lt;code&gt;await&lt;/code&gt; no bloquea el hilo?
&lt;/h3&gt;

&lt;h3&gt;
  
  
  ¿Qué preguntas te quedan sin responder sobre el &lt;code&gt;@MainActor&lt;/code&gt; y cómo encaja con lo aprendido aquí?
&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] ¿Cuándo usar AsyncStream en lugar de AsyncSequence?</title>
      <dc:creator>GoyesDev</dc:creator>
      <pubDate>Tue, 28 Apr 2026 10:59:43 +0000</pubDate>
      <link>https://dev.to/david_goyes_a488f58a17a53/sc-58j0</link>
      <guid>https://dev.to/david_goyes_a488f58a17a53/sc-58j0</guid>
      <description>&lt;h2&gt;
  
  
  Preguntas
&lt;/h2&gt;

&lt;h3&gt;
  
  
  ¿Cuándo debería usar &lt;code&gt;AsyncSequence&lt;/code&gt; en lugar de &lt;code&gt;AsyncStream&lt;/code&gt;, y viceversa?
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://developer.apple.com/documentation/Swift/AsyncSequence" rel="noopener noreferrer"&gt;&lt;code&gt;AsyncSequence&lt;/code&gt;&lt;/a&gt; es la abstracción a la que debería acoplarme, mientras que &lt;a href="https://developer.apple.com/documentation/swift/asyncstream" rel="noopener noreferrer"&gt;&lt;code&gt;AsyncStream&lt;/code&gt;&lt;/a&gt; es una implementación concreta de &lt;code&gt;AsyncSequence&lt;/code&gt; que puedo utilizar para emitir eventos.&lt;/p&gt;

&lt;h3&gt;
  
  
  ¿Qué ventajas ofrece &lt;code&gt;AsyncStream&lt;/code&gt; para casos de uso comunes?
&lt;/h3&gt;

&lt;p&gt;Se puede usar directamente esta implementación concreta, definiendo el closure que recibe un &lt;code&gt;continuation&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;El API de &lt;code&gt;AsyncStream&lt;/code&gt; es fácil de recordar y escribir, y especialmente útil para crear puentes entre delegados, llamados a closures y emisión manual de eventos.&lt;/p&gt;

&lt;h3&gt;
  
  
  ¿Cómo se relacionan &lt;code&gt;AsyncSequence&lt;/code&gt; y &lt;code&gt;AsyncStream&lt;/code&gt; entre sí?
&lt;/h3&gt;

&lt;p&gt;&lt;code&gt;AsyncStream&lt;/code&gt; conforma &lt;code&gt;AsyncSequence&lt;/code&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  ¿Qué ejemplo concreto usa el artículo para ilustrar el puente de delegates con &lt;code&gt;AsyncThrowingStream&lt;/code&gt;?
&lt;/h3&gt;

&lt;p&gt;En el artículo se creó un &lt;code&gt;LocationMonitor&lt;/code&gt; que funciona como delegado (&lt;code&gt;CLLocationManagerDelegate&lt;/code&gt;) de un &lt;code&gt;CLLocationManager&lt;/code&gt;. Este &lt;code&gt;LocationMonitor&lt;/code&gt; tenía un atributo llamado &lt;code&gt;stream&lt;/code&gt; de tipo &lt;code&gt;AsyncThrowingStream&amp;lt;CLLocation, Error&amp;gt;&lt;/code&gt;, manejado con un &lt;code&gt;continuation&lt;/code&gt; de tipo &lt;code&gt;AsyncThrowingStream&amp;lt;CLLocation, Error&amp;gt;.Continuation?&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Cada vez que el &lt;code&gt;LocationMonitor&lt;/code&gt; recibía un evento como delegado de &lt;code&gt;LocationMonitor&lt;/code&gt;, emitía un evento al &lt;code&gt;stream&lt;/code&gt; a través del &lt;code&gt;continuation&lt;/code&gt; con &lt;a href="https://developer.apple.com/documentation/swift/asyncthrowingstream/continuation/yield(_:)" rel="noopener noreferrer"&gt;&lt;code&gt;yield(_:)&lt;/code&gt;&lt;/a&gt;, y &lt;a href="https://developer.apple.com/documentation/swift/asyncthrowingstream/continuation/finish(throwing:)" rel="noopener noreferrer"&gt;&lt;code&gt;finish(throwing:)&lt;/code&gt;&lt;/a&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  ¿Cómo funciona el método &lt;code&gt;AsyncStream.init(unfolding:oncancel:)&lt;/code&gt; en el ejemplo del servicio de &lt;code&gt;ping&lt;/code&gt;?
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://developer.apple.com/documentation/swift/asyncstream/init(unfolding:oncancel:)" rel="noopener noreferrer"&gt;&lt;code&gt;AsyncStream.init(unfolding:onCancel:)&lt;/code&gt;&lt;/a&gt; recibe un closure asíncrono que produce elementos (&lt;code&gt;unfolding&lt;/code&gt;) y otro opcional que se maneja la cancelación (&lt;code&gt;oncancel&lt;/code&gt;).&lt;/p&gt;

&lt;h3&gt;
  
  
  ¿Por qué el artículo compara &lt;code&gt;AsyncSequence&lt;/code&gt; con el protocolo &lt;code&gt;Sequence&lt;/code&gt; en Swift?
&lt;/h3&gt;

&lt;p&gt;&lt;code&gt;AsyncSequence&lt;/code&gt; es la versión asíncrona de &lt;code&gt;Sequence&lt;/code&gt;. Además, el artículo menciona que muy pocas veces implementamos el protocolo &lt;code&gt;Sequence&lt;/code&gt;, sino que son mayormente otros tipos de datos del SDK de iOS que lo conforman - Básicamente nosotros como desarrolladores tendríamos la misma relación con &lt;code&gt;AsyncSequence&lt;/code&gt;.&lt;/p&gt;




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

&lt;h3&gt;
  
  
  Sin releer, ¿puedes explicar con tus palabras cuándo elegirías &lt;code&gt;AsyncStream&lt;/code&gt; sobre &lt;code&gt;AsyncSequence&lt;/code&gt;?
&lt;/h3&gt;

&lt;h3&gt;
  
  
  ¿Qué hace la &lt;code&gt;continuation&lt;/code&gt; en el ejemplo de &lt;code&gt;LocationMonitor&lt;/code&gt; y por qué es clave?
&lt;/h3&gt;

&lt;h3&gt;
  
  
  ¿Qué APIs estándar de Apple mencionadas en el artículo conforman &lt;code&gt;AsyncSequence&lt;/code&gt;?
&lt;/h3&gt;




&lt;h3&gt;
  
  
  Repaso final
&lt;/h3&gt;

&lt;h3&gt;
  
  
  ¿Cuál es la conclusión principal del artículo sobre cuál opción usar en la mayoría de proyectos reales?
&lt;/h3&gt;

&lt;h3&gt;
  
  
  ¿Qué limitación menciona el artículo sobre el ejemplo de &lt;code&gt;LocationMonitor&lt;/code&gt;?
&lt;/h3&gt;

&lt;h3&gt;
  
  
  ¿En qué escenarios reales, mencionados explícitamente, tiene más sentido usar &lt;code&gt;AsyncStream&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] AsyncStream y AsyncThrowingStream</title>
      <dc:creator>GoyesDev</dc:creator>
      <pubDate>Tue, 28 Apr 2026 01:33:44 +0000</pubDate>
      <link>https://dev.to/david_goyes_a488f58a17a53/sc-asyncstream-y-asyncthrowingstream-i9</link>
      <guid>https://dev.to/david_goyes_a488f58a17a53/sc-asyncstream-y-asyncthrowingstream-i9</guid>
      <description>&lt;h2&gt;
  
  
  Preguntas
&lt;/h2&gt;

&lt;h3&gt;
  
  
  ¿Qué es un &lt;code&gt;AsyncStream&lt;/code&gt; y en qué se diferencia de un &lt;code&gt;AsyncThrowingStream&lt;/code&gt;?
&lt;/h3&gt;

&lt;p&gt;Un &lt;code&gt;AsyncStream&lt;/code&gt; es un &lt;code&gt;AsyncSequence&lt;/code&gt; que puede emitir eventos de progreso y fin con base en un &lt;a href="https://developer.apple.com/documentation/swift/asyncstream/continuation" rel="noopener noreferrer"&gt;&lt;code&gt;AsyncStream.Continuation&lt;/code&gt;&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Es muy parecido a un &lt;code&gt;Publisher&lt;/code&gt; de Combine, con la diferencia que solo admite un suscriptor.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;AsyncThrowingStream&lt;/code&gt; es la versión que arroja error de &lt;code&gt;AsyncStream&lt;/code&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  ¿Por qué podría querer reemplazar un closure de progreso/completación con un &lt;code&gt;AsyncThrowingStream&lt;/code&gt;?
&lt;/h3&gt;

&lt;p&gt;Facilita la integración del API de &lt;code&gt;async&lt;/code&gt;/&lt;code&gt;await&lt;/code&gt; en lugar de una integración basada en closures. Además, &lt;code&gt;AsyncStream&lt;/code&gt; permite poder iterar con &lt;code&gt;for try await&lt;/code&gt; en lugar de anidar closures, lo que hace el flujo más lineal y legible.&lt;/p&gt;

&lt;h3&gt;
  
  
  ¿Qué sucede si no se llama a &lt;code&gt;continuation.finish()&lt;/code&gt; al terminar un &lt;code&gt;stream&lt;/code&gt;?
&lt;/h3&gt;

&lt;p&gt;La implementación se va a quedar colgada sin terminar. El código que itera el stream con &lt;code&gt;for try await&lt;/code&gt; nunca avanza más allá del loop porque el stream nunca emite el evento de terminación.&lt;/p&gt;

&lt;h3&gt;
  
  
  ¿Qué son las &lt;code&gt;buffer policies&lt;/code&gt; y cuándo tendría sentido usar cada una?
&lt;/h3&gt;

&lt;p&gt;Las "buffer policies" define qué hacer con los valores emitidos cuando no hay ningún consjmidor leyendo aún. Es decir: regulan el buffer previo a la lecutra, no a la entrega en tiempo real. En el artículo se mencionan:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://developer.apple.com/documentation/swift/asyncstream/continuation/bufferingpolicy/unbounded" rel="noopener noreferrer"&gt;&lt;code&gt;AsyncStream.Continuation.BufferingPolicy.unbounded&lt;/code&gt;&lt;/a&gt;: El suscriptor recibe todos los eventos pasados emitidos por el &lt;code&gt;AsyncStream&lt;/code&gt; antes de la suscripción.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://developer.apple.com/documentation/swift/asyncstream/continuation/bufferingpolicy/bufferingoldest(_:)" rel="noopener noreferrer"&gt;&lt;code&gt;AsyncStream.Continuation.BufferingPolicy.bufferingOldest(_:)&lt;/code&gt;&lt;/a&gt;: El suscriptor recibe los primeros (oldest) &lt;code&gt;n&lt;/code&gt; eventos emitidos por el &lt;code&gt;AsyncStream&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://developer.apple.com/documentation/swift/asyncstream/continuation/bufferingpolicy/bufferingnewest(_:)" rel="noopener noreferrer"&gt;AsyncStream.Continuation.BufferingPolicy.bufferingNewest(_:)&lt;/a&gt;: El suscriptor recibe los últimos (newest) &lt;code&gt;n&lt;/code&gt; eventos emitidos por el &lt;code&gt;AsyncStream&lt;/code&gt;. En el artículo ponen de ejemplo que al usar &lt;code&gt;bufferingnewest(0)&lt;/code&gt;, se ignoran todos los eventos pasados emitidos por el &lt;code&gt;AsyncStream&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  ¿En qué se diferencia un &lt;code&gt;AsyncStream&lt;/code&gt; de un &lt;code&gt;publisher&lt;/code&gt; de &lt;code&gt;Combine&lt;/code&gt;?
&lt;/h3&gt;

&lt;p&gt;El &lt;code&gt;Publisher&lt;/code&gt; de Combine puede tener varios suscriptores. El &lt;code&gt;AsyncStream&lt;/code&gt; solo puede tener uno.&lt;/p&gt;

&lt;h3&gt;
  
  
  ¿Cómo se usa el &lt;code&gt;continuation&lt;/code&gt; para enviar valores, manejar errores y terminar el &lt;code&gt;stream&lt;/code&gt;?
&lt;/h3&gt;

&lt;p&gt;Sobre el &lt;code&gt;continuation&lt;/code&gt; se pueden usar los siguientes métodos:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://developer.apple.com/documentation/swift/asyncstream/continuation/yield(with:)" rel="noopener noreferrer"&gt;&lt;code&gt;yield(with:)&lt;/code&gt;&lt;/a&gt;: Para emitir un elemento de tipo &lt;code&gt;Result&amp;lt;Element,Never&amp;gt; en un&lt;/code&gt;AsyncStream`.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://developer.apple.com/documentation/swift/asyncthrowingstream/continuation/yield(with:)" rel="noopener noreferrer"&gt;&lt;code&gt;yield(with:)&lt;/code&gt;&lt;/a&gt;: Para emitir un elemento de tipo &lt;code&gt;Result&amp;lt;Element,Failure&amp;gt; en un &lt;/code&gt;AsyncThrowingStream`.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://developer.apple.com/documentation/swift/asyncstream/continuation/finish()" rel="noopener noreferrer"&gt;&lt;code&gt;finish()&lt;/code&gt;&lt;/a&gt;: Para cerrar el Stream sin emitir error.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://developer.apple.com/documentation/swift/asyncthrowingstream/continuation/finish(throwing:)" rel="noopener noreferrer"&gt;&lt;code&gt;finish(throwing:)&lt;/code&gt;&lt;/a&gt;: Para cerrar el Stream emitiendo un error&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://developer.apple.com/documentation/swift/asyncstream/continuation/ontermination" rel="noopener noreferrer"&gt;&lt;code&gt;onTermination&lt;/code&gt;&lt;/a&gt;: Suscribe un closure para ejecutar algún trabajo cuando termina el stream. Este sirve para hacer labores de limpieza o depuración.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  ¿Qué hace el &lt;code&gt;callback onTermination&lt;/code&gt; y para qué casos de uso es útil?
&lt;/h3&gt;

&lt;p&gt;Suscribe un closure para ejecutar algún trabajo cuando termina el stream. Este sirve para hacer labores de limpieza o depuración.&lt;/p&gt;

&lt;h3&gt;
  
  
  ¿Cómo y cuándo se cancela un stream, y qué efecto tiene la cancelación?
&lt;/h3&gt;

&lt;p&gt;Un Stream se cancela cuando el contexto asíncrono que lo envuelve es cancelado (e.g. &lt;code&gt;Task.cancel()&lt;/code&gt;).&lt;/p&gt;

&lt;p&gt;El stream se termina (no en error, ni en success), sino que se invoca &lt;code&gt;onTermination&lt;/code&gt; con la causa (i.e. "termination reason: cancelled")&lt;/p&gt;

&lt;p&gt;No hay forma de cancelar el stream explícitamente, solo de forma indirectamente a través del &lt;code&gt;Task&lt;/code&gt; que lo envuelve.&lt;/p&gt;

&lt;h3&gt;
  
  
  ¿Por qué no es seguro tener múltiples consumidores de un mismo &lt;code&gt;AsyncStream&lt;/code&gt;?
&lt;/h3&gt;

&lt;p&gt;Como solo puede tener un suscriptor, no se sabe a cuál le va a entregar el valor. Los valroes se reparten entre los consumidores en lugar de duplicarse - Cada valor lo recibe uno solo, de forma impredecible.&lt;/p&gt;




&lt;h2&gt;
  
  
  Recordar sin mirar el texto
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Explica con tus propias palabras el ciclo de vida de un &lt;code&gt;AsyncThrowingStream&lt;/code&gt;, desde su creación hasta su terminación.
&lt;/h3&gt;

&lt;h3&gt;
  
  
  ¿Cuáles son las tres razones posibles por las que un stream puede terminar y cómo se reporta cada una?
&lt;/h3&gt;

&lt;h3&gt;
  
  
  Sin mirar el código, describe cómo transformarías el &lt;code&gt;FileDownloader&lt;/code&gt; basado en closures a uno basado en &lt;code&gt;AsyncThrowingStream&lt;/code&gt;.
&lt;/h3&gt;




&lt;h2&gt;
  
  
  Revisión y conexión de ideas
&lt;/h2&gt;

&lt;h3&gt;
  
  
  ¿En qué escenarios concretos de tu propio código usarías un &lt;code&gt;AsyncStream&lt;/code&gt; en lugar de &lt;code&gt;Combine&lt;/code&gt; o callbacks?
&lt;/h3&gt;

&lt;h3&gt;
  
  
  ¿Cuál es la limitación más importante de &lt;code&gt;AsyncStream&lt;/code&gt; mencionada en el artículo y cómo se puede mitigar?
&lt;/h3&gt;

&lt;h3&gt;
  
  
  ¿Qué errores de programación comunes advierte el artículo y qué estrategias propone para detectarlos?
&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] Trabajando con secuencias asíncronas</title>
      <dc:creator>GoyesDev</dc:creator>
      <pubDate>Mon, 27 Apr 2026 23:31:04 +0000</pubDate>
      <link>https://dev.to/david_goyes_a488f58a17a53/sc-trabajando-con-secuencias-asincronas-3ego</link>
      <guid>https://dev.to/david_goyes_a488f58a17a53/sc-trabajando-con-secuencias-asincronas-3ego</guid>
      <description>&lt;h2&gt;
  
  
  Preguntas
&lt;/h2&gt;

&lt;h3&gt;
  
  
  ¿Qué es un &lt;code&gt;AsyncSequence&lt;/code&gt; y en qué se diferencia de un &lt;code&gt;Sequence&lt;/code&gt; normal?
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://developer.apple.com/documentation/Swift/AsyncSequence" rel="noopener noreferrer"&gt;&lt;code&gt;AsyncSequence&lt;/code&gt;&lt;/a&gt; es un tipo de dato que provee acceso secuencial e iterativo a una colección de forma asíncrona.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;AsyncSequence&lt;/code&gt; es un hermano de &lt;code&gt;Sequence&lt;/code&gt; que prácticamente puede hacer todo lo que hace &lt;code&gt;Sequence&lt;/code&gt; (como &lt;a href="https://developer.apple.com/documentation/swift/asyncsequence/contains(_:)" rel="noopener noreferrer"&gt;&lt;code&gt;contains(_:)&lt;/code&gt;&lt;/a&gt;, &lt;a href="https://developer.apple.com/documentation/swift/asyncsequence/map(_:)-1q1k3" rel="noopener noreferrer"&gt;&lt;code&gt;map(_:)&lt;/code&gt;&lt;/a&gt;) con la diferencia que los datos se recorren de forma asíncrona.&lt;/p&gt;

&lt;h3&gt;
  
  
  ¿Qué rol cumplen &lt;code&gt;AsyncIterator&lt;/code&gt; y el método &lt;code&gt;next()&lt;/code&gt; dentro de una secuencia asíncrona?
&lt;/h3&gt;

&lt;p&gt;Un tipo de dato que conforme el protocolo &lt;code&gt;AsyncSequence&lt;/code&gt; debe definir el método &lt;a href="https://developer.apple.com/documentation/swift/asyncsequence/makeasynciterator()" rel="noopener noreferrer"&gt;&lt;code&gt;makeAsyncIterator()&lt;/code&gt;&lt;/a&gt; que devuelve una instancia que conforme el protocolo &lt;a href="https://developer.apple.com/documentation/swift/asynciteratorprotocol" rel="noopener noreferrer"&gt;&lt;code&gt;AsyncIteratorProtocol&lt;/code&gt;&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Un &lt;code&gt;AsyncIterator&lt;/code&gt; es como un &lt;a href="https://developer.apple.com/documentation/swift/iteratorprotocol" rel="noopener noreferrer"&gt;&lt;code&gt;IteratorProtocol&lt;/code&gt;&lt;/a&gt; con la diferencia que debe recorrer una colección asíncrona a través del método &lt;a href="https://developer.apple.com/documentation/swift/asynciteratorprotocol/next()" rel="noopener noreferrer"&gt;&lt;code&gt;next() async&lt;/code&gt;&lt;/a&gt; que puede tener puntos de suspensión y, retorna el siguiente valor de la colección o &lt;code&gt;nil&lt;/code&gt; si ya terminó el trabajo.&lt;/p&gt;

&lt;h3&gt;
  
  
  ¿Cómo se indica el fin de la iteración en un &lt;code&gt;AsyncSequence&lt;/code&gt; personalizado?
&lt;/h3&gt;

&lt;p&gt;Se indica el fin de una iteración devolviendo &lt;code&gt;nil&lt;/code&gt;. Esto puede ocurrir por dos razones:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;se alcanzó el límite configurado&lt;/li&gt;
&lt;li&gt;la tarea fue cancelada (&lt;code&gt;Task.isCancelled&lt;/code&gt;).&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  ¿Por qué se recomienda usar &lt;code&gt;AsyncStream&lt;/code&gt; en lugar de implementar &lt;code&gt;AsyncSequence&lt;/code&gt; directamente?
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://developer.apple.com/documentation/swift/asyncstream" rel="noopener noreferrer"&gt;&lt;code&gt;AsyncStream&lt;/code&gt;&lt;/a&gt; es más conveniente de configurar que &lt;code&gt;AsyncSequence&lt;/code&gt;, porque al usar este último se debe un &lt;code&gt;AsyncIterator&lt;/code&gt; y manejar su estado.&lt;/p&gt;

&lt;h3&gt;
  
  
  ¿Qué operadores de &lt;code&gt;Sequence&lt;/code&gt; están disponibles también para secuencias asíncronas?
&lt;/h3&gt;

&lt;p&gt;Métodos como:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://developer.apple.com/documentation/swift/asyncsequence/contains(where:)" rel="noopener noreferrer"&gt;&lt;code&gt;contains(where:)&lt;/code&gt;&lt;/a&gt; - Tener cuidado que métodos como este esperan a que la secuencia asíncrona termine de emitir elementos y se puede quedar esperando indefinidamente.&lt;/li&gt;
&lt;li&gt;&lt;a href="https://developer.apple.com/documentation/swift/asyncsequence/map(_:)-70wgb" rel="noopener noreferrer"&gt;&lt;code&gt;map(_:)&lt;/code&gt;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://developer.apple.com/documentation/swift/asyncsequence/filter(_:)-435af" rel="noopener noreferrer"&gt;&lt;code&gt;filter(_:)&lt;/code&gt;&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Identifica cómo el protocolo &lt;code&gt;AsyncSequence&lt;/code&gt; define el acceso a valores sin generarlos por sí mismo.
&lt;/h3&gt;

&lt;p&gt;&lt;code&gt;AsyncSequence&lt;/code&gt; se encarga de la construcción del &lt;code&gt;AsyncIteratorProtocol&lt;/code&gt;, quien técnicamente es el encargado de generar los elementos en el método &lt;code&gt;next() async&lt;/code&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Analiza cómo la cancelación con &lt;code&gt;Task.isCancelled&lt;/code&gt; interactúa con el ciclo de vida de la secuencia.
&lt;/h3&gt;

&lt;p&gt;Entro del contexto de &lt;a href="https://developer.apple.com/documentation/swift/asynciteratorprotocol/next()" rel="noopener noreferrer"&gt;&lt;code&gt;next() async&lt;/code&gt;&lt;/a&gt; es &lt;strong&gt;de vital importancia&lt;/strong&gt; verificar que la tarea no haya sido cancelada con &lt;code&gt;Task.isCancelled&lt;/code&gt; (sin esta verificación, la secuencia seguiría emitiendo valores a pesar de que la tarea hubiera sido cancelada). Si lo fue, entonces retornar &lt;code&gt;nil&lt;/code&gt;.&lt;/p&gt;




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

&lt;h3&gt;
  
  
  Explica con tus palabras qué hace el método &lt;code&gt;next()&lt;/code&gt; en el ejemplo &lt;code&gt;Counter&lt;/code&gt;.
&lt;/h3&gt;

&lt;h3&gt;
  
  
  ¿Cómo se usa &lt;code&gt;for await&lt;/code&gt; para iterar sobre un &lt;code&gt;AsyncSequence&lt;/code&gt; y por qué es necesario el &lt;code&gt;await&lt;/code&gt;?
&lt;/h3&gt;

&lt;h3&gt;
  
  
  Menciona al menos dos operadores que se pueden aplicar sobre una secuencia asíncrona y describe su efecto.
&lt;/h3&gt;

&lt;h3&gt;
  
  
  ¿Qué ocurre si una secuencia asíncrona nunca termina y usas un método como &lt;code&gt;contains&lt;/code&gt;?
&lt;/h3&gt;




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

&lt;h3&gt;
  
  
  ¿En qué situaciones reales tiene sentido usar un &lt;code&gt;AsyncSequence&lt;/code&gt; en lugar de un &lt;code&gt;array&lt;/code&gt; estático?
&lt;/h3&gt;

&lt;h3&gt;
  
  
  ¿Por qué el artículo dice que un &lt;code&gt;AsyncSequence&lt;/code&gt; "prepara para valores asíncronos" aunque no siempre los envíe de forma asíncrona?
&lt;/h3&gt;

&lt;h3&gt;
  
  
  ¿Qué relación existe entre los task groups vistos en lecciones anteriores y el concepto de &lt;code&gt;AsyncSequence&lt;/code&gt;?
&lt;/h3&gt;

&lt;h3&gt;
  
  
  Después de leer este módulo, ¿qué preguntas tienes sobre &lt;code&gt;AsyncStream&lt;/code&gt;, el siguiente tema?
&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] Usando un Mutex como alternativa a los actores</title>
      <dc:creator>GoyesDev</dc:creator>
      <pubDate>Mon, 27 Apr 2026 21:29:37 +0000</pubDate>
      <link>https://dev.to/david_goyes_a488f58a17a53/sc-usando-un-mutex-como-alternativa-a-los-actores-18bo</link>
      <guid>https://dev.to/david_goyes_a488f58a17a53/sc-usando-un-mutex-como-alternativa-a-los-actores-18bo</guid>
      <description>&lt;h2&gt;
  
  
  Preguntas
&lt;/h2&gt;

&lt;h3&gt;
  
  
  ¿Qué es un &lt;code&gt;Mutex&lt;/code&gt; y en qué se diferencia de un &lt;code&gt;Lock&lt;/code&gt;?
&lt;/h3&gt;

&lt;p&gt;Un &lt;code&gt;Mutex&lt;/code&gt; es un tipo de &lt;code&gt;Lock&lt;/code&gt; del framework &lt;a href="https://developer.apple.com/documentation/synchronization" rel="noopener noreferrer"&gt;&lt;code&gt;Synchronization&lt;/code&gt;&lt;/a&gt; usado para sincronizar accesos a una variable a través del método &lt;a href="https://developer.apple.com/documentation/synchronization/mutex/withlock(_:)" rel="noopener noreferrer"&gt;&lt;code&gt;withLock(_:)&lt;/code&gt;&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;El método &lt;code&gt;withLock&lt;/code&gt; es equivalente a hacer:&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="n"&gt;mutex&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;defer&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="n"&gt;mutex&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="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="nf"&gt;body&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Observar que &lt;code&gt;value&lt;/code&gt; es un valor &lt;code&gt;inout&lt;/code&gt;, que se devuelve el valor generado por &lt;code&gt;try body(&amp;amp;value)&lt;/code&gt; y que puede arrojar un error.&lt;/p&gt;

&lt;p&gt;La diferencia importante entre &lt;code&gt;Mutex&lt;/code&gt; y &lt;code&gt;Lock&lt;/code&gt; es que usando &lt;code&gt;Lock&lt;/code&gt;, el tipo de dato no es &lt;code&gt;Sendable&lt;/code&gt; (tendría que marcarse con &lt;code&gt;@unchecked Sendable&lt;/code&gt;). En cambio, &lt;code&gt;Mutex&lt;/code&gt; sí es &lt;code&gt;Sendable&lt;/code&gt; porque encapsula su valor internamente y controla todo acceso a él.&lt;/p&gt;

&lt;h3&gt;
  
  
  ¿Por qué Apple introdujo un &lt;code&gt;Mutex&lt;/code&gt; si ya existen los actores en Swift Concurrency?
&lt;/h3&gt;

&lt;p&gt;&lt;code&gt;Mutex&lt;/code&gt; es una aproximación bloqueante síncrona que, en ocasiones, puede servir en lugar de un &lt;code&gt;actor&lt;/code&gt; asíncrono. Usar el actor asíncrono implica un "overhead" de "scheduling", además de que el invocador debe estar en un contexto síncrono.&lt;/p&gt;

&lt;p&gt;El &lt;code&gt;Mutex&lt;/code&gt; es útil cuando el trabajo protegido es breve y el bloqueo es más eficiente que suspender y reanudar una tarea.&lt;/p&gt;

&lt;h3&gt;
  
  
  ¿Desde qué versiones de iOS y macOS está disponible el framework &lt;code&gt;Synchronization&lt;/code&gt;?
&lt;/h3&gt;

&lt;p&gt;iOS 18 y macOS 15.&lt;/p&gt;

&lt;h3&gt;
  
  
  ¿Cómo se usa el método &lt;code&gt;withLock&lt;/code&gt; y qué tipo de acceso proporciona al valor protegido?
&lt;/h3&gt;

&lt;p&gt;Debido a que el parámetro que recibe &lt;code&gt;withLock&lt;/code&gt; es &lt;code&gt;inout&lt;/code&gt;, entonces da un acceso por referencia.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;withLock&lt;/code&gt; se usa pasando un closure que puede modificar el valor protegido y puede retornar algún valor. En el ejemplo del artículo teníamos:&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;currentCount&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;count&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;withLock&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;currentCount&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;currentCount&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;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;count&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;withLock&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;currentCount&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt;
    &lt;span class="n"&gt;currentCount&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;
  
  
  ¿Cómo permite el &lt;code&gt;Mutex&lt;/code&gt; trabajar con tipos no-&lt;code&gt;Sendable&lt;/code&gt; como &lt;code&gt;NSBezierPath&lt;/code&gt;?
&lt;/h3&gt;

&lt;p&gt;A pesar de que &lt;code&gt;NSBezierPath&lt;/code&gt; es no-&lt;code&gt;Sendable&lt;/code&gt;, se puede crear un &lt;code&gt;Mutex&lt;/code&gt;, constante (&lt;code&gt;let&lt;/code&gt;), que envuelva al &lt;code&gt;NSBezierPath&lt;/code&gt; y modificar el path protegido.&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;path&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kt"&gt;Mutex&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;NSBezierPath&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;NSBezierPath&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;storeTouch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;_&lt;/span&gt; &lt;span class="nv"&gt;point&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;NSPoint&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;withLock&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;path&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt;
    &lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;move&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;to&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;point&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;h3&gt;
  
  
  ¿Qué sucede cuando múltiples hilos intentan adquirir un &lt;code&gt;Mutex&lt;/code&gt; al mismo tiempo?
&lt;/h3&gt;

&lt;p&gt;Si un hilo trata de tomar el &lt;code&gt;Mutex&lt;/code&gt; y este ya fue tomado, entonces el hilo permanece bloqueado hasta que el &lt;code&gt;Mutex&lt;/code&gt; sea liberado.&lt;/p&gt;




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

&lt;h3&gt;
  
  
  ¿En qué situaciones concretas es preferible usar un &lt;code&gt;Mutex&lt;/code&gt; en lugar de un actor?
&lt;/h3&gt;

&lt;h3&gt;
  
  
  ¿Cómo se puede lanzar un error desde dentro del closure &lt;code&gt;withLock&lt;/code&gt;?
&lt;/h3&gt;




&lt;h2&gt;
  
  
  Repaso y reflexión
&lt;/h2&gt;

&lt;h3&gt;
  
  
  ¿Cuál es la conclusión principal del artículo respecto a la elección entre actores y &lt;code&gt;Mutex&lt;/code&gt;?
&lt;/h3&gt;

&lt;h3&gt;
  
  
  ¿Qué ventajas y desventajas tiene cada herramienta según el contexto del proyecto?
&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] Usando Taks inmediatas</title>
      <dc:creator>GoyesDev</dc:creator>
      <pubDate>Mon, 27 Apr 2026 21:02:34 +0000</pubDate>
      <link>https://dev.to/david_goyes_a488f58a17a53/sc-usando-taks-inmediatas-o73</link>
      <guid>https://dev.to/david_goyes_a488f58a17a53/sc-usando-taks-inmediatas-o73</guid>
      <description>&lt;h2&gt;
  
  
  Preguntas guía
&lt;/h2&gt;

&lt;h3&gt;
  
  
  ¿Cuál es la diferencia fundamental entre &lt;code&gt;Task&lt;/code&gt; y &lt;code&gt;Task.immediate&lt;/code&gt; en cuanto a cuándo empieza a ejecutarse el trabajo?
&lt;/h3&gt;

&lt;p&gt;&lt;code&gt;Task.immediate&lt;/code&gt; empieza ejecutando de forma síncrona el código definido dentro del bloque de trabajo, hasta que encuentra el primer punto de suspensión real. En este punto, continua con el trabajo fuera del &lt;code&gt;Task&lt;/code&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  ¿Qué significa exactamente que una tarea inmediata "corre hasta el primer punto de suspensión real"?
&lt;/h3&gt;

&lt;p&gt;El primer punto de suspensión real aparece cuando alguna operación costosa (e.g. I/O, actor ocupado, etc) cause que la tarea tenga que esperar.&lt;/p&gt;

&lt;p&gt;Si antes de ese punto hay una salida temprana o un código síncrono simple, &lt;code&gt;Task.immediate&lt;/code&gt; puede ejecutarlo como si fuera síncrono (sin cambiar al contexto asíncrono).&lt;/p&gt;

&lt;h3&gt;
  
  
  ¿En qué escenarios concretos tiene sentido usar &lt;code&gt;Task.immediate&lt;/code&gt; en lugar de un &lt;code&gt;Task&lt;/code&gt; regular?
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Empezar la ejecución de código asíncrono desde un contexto síncrono, preservando el orden.&lt;/li&gt;
&lt;li&gt;Necesito cambiar rápidamente parte del estado del actor que va a ser usado después del &lt;code&gt;Task.immediate&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Salir tempranamente del bloque definido en &lt;code&gt;Task.immediate&lt;/code&gt; con una condición sencilla.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  ¿Qué es el &lt;code&gt;overhang&lt;/code&gt; y por qué es especialmente peligroso en el &lt;code&gt;MainActor&lt;/code&gt;?
&lt;/h3&gt;

&lt;p&gt;&lt;code&gt;overhang&lt;/code&gt; es ejecutar una cantidad significativa de código síncrono en un executor antes del primer punto de suspensión.&lt;/p&gt;

&lt;p&gt;Si defino un método como &lt;code&gt;@MainActor&lt;/code&gt;, y dentro de &lt;code&gt;Task.immediate&lt;/code&gt; empiezo haciendo un trabajo síncrono muy demorado (e.g. que tome 300 milliseconds), esto va a bloquear la interfaz gráfica.&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;func&lt;/span&gt; &lt;span class="nf"&gt;handleSearchQuery&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;_&lt;/span&gt; &lt;span class="nv"&gt;query&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="kt"&gt;Task&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;immediate&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;results&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;expensiveLocalSearch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;query&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;updateResults&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;results&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;h3&gt;
  
  
  ¿Cómo se comporta &lt;code&gt;Task.immediate { @MainActor in ... }&lt;/code&gt; cuando el &lt;code&gt;executor&lt;/code&gt; actual no es el &lt;code&gt;MainActor&lt;/code&gt;?
&lt;/h3&gt;

&lt;p&gt;Cuando se usa &lt;code&gt;Task.immediate { @MainActor in ... }&lt;/code&gt; y el executor actual es &lt;code&gt;MainActor&lt;/code&gt;, en la práctica es como si tuviéramos código síncrono.&lt;/p&gt;

&lt;p&gt;Sin embargo, llamar &lt;code&gt;Task.immediate { @MainActor in ... }&lt;/code&gt; desde otro actor va a tener el mismo efecto que &lt;code&gt;Task{ @MainActor in ... }&lt;/code&gt; (i.e. como si fuera código asíncrono e invirtiendo recursos para cambiar de contexto).&lt;/p&gt;

&lt;h3&gt;
  
  
  ¿Qué diferencia hay entre &lt;code&gt;Task.immediateDetached&lt;/code&gt; y &lt;code&gt;Task.detached&lt;/code&gt;?
&lt;/h3&gt;

&lt;p&gt;&lt;code&gt;Task.immediateDetached&lt;/code&gt; (igual que su contraparte &lt;code&gt;Task.detached&lt;/code&gt;) no hereda el contexto del actor, los valores locales de &lt;code&gt;Task&lt;/code&gt; o la cancelación.&lt;/p&gt;

&lt;p&gt;El aspecto "immediate" solo cambia &lt;em&gt;cuándo&lt;/em&gt; empieza a ejecutar la tarea.&lt;/p&gt;

&lt;h3&gt;
  
  
  ¿Por qué &lt;code&gt;addImmediateTask&lt;/code&gt; dentro de un &lt;code&gt;TaskGroup&lt;/code&gt; puede hacer que el trabajo se vuelva serial en lugar de paralelo?
&lt;/h3&gt;

&lt;p&gt;La idea de usar un &lt;code&gt;TaskGroup&lt;/code&gt; es para que las tareas se ejecuten de forma paralela. Si ellas hacen bastante trabajo síncrono, entonces prácticamente puede convertirse en una ejecución serial de las mismas.&lt;/p&gt;

&lt;p&gt;El hecho de que una tarea &lt;code&gt;immediate&lt;/code&gt; bloquee al executor antes de que se añada la siguiente tarea al grupo aparenta como si solo se ejecutara una tarea a la vez.&lt;/p&gt;




&lt;h2&gt;
  
  
  Comprensión propia
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Sin mirar el texto, ¿puedes explicar con tus palabras qué ocurre paso a paso cuando se llama a &lt;code&gt;Task.immediate&lt;/code&gt; desde una función sincrónica en el &lt;code&gt;MainActor&lt;/code&gt;?
&lt;/h3&gt;

&lt;h3&gt;
  
  
  ¿Cuáles son los tres casos que el autor menciona como válidos para usar tareas inmediatas?
&lt;/h3&gt;




&lt;h2&gt;
  
  
  Repaso crítico
&lt;/h2&gt;

&lt;h3&gt;
  
  
  ¿Qué criterio usarías para decidir entre &lt;code&gt;Task&lt;/code&gt;, &lt;code&gt;Task.immediate&lt;/code&gt; y &lt;code&gt;Task.detached&lt;/code&gt; en un caso real de tu propio código?
&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] Usar un ejecutor de actor personalizado</title>
      <dc:creator>GoyesDev</dc:creator>
      <pubDate>Sat, 25 Apr 2026 16:36:02 +0000</pubDate>
      <link>https://dev.to/david_goyes_a488f58a17a53/sc-usar-un-ejecutor-de-actor-personalizado-ocm</link>
      <guid>https://dev.to/david_goyes_a488f58a17a53/sc-usar-un-ejecutor-de-actor-personalizado-ocm</guid>
      <description>&lt;h2&gt;
  
  
  Preguntas
&lt;/h2&gt;

&lt;h3&gt;
  
  
  ¿En qué situaciones el executor por defecto de Swift resulta insuficiente y cuándo debería considerarse un ejecutor personalizado?
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;No se quiere usar el pool de hilos global cooperativo.&lt;/li&gt;
&lt;li&gt;Se quiere usar una cola serial específica.&lt;/li&gt;
&lt;li&gt;Se quiere enganchar un hilo específico.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Puede ser el caso de una biblioteca de terceros que espera recibir un &lt;code&gt;DispatchQueue&lt;/code&gt; serial para orquestar sus operaciones.&lt;/p&gt;

&lt;h3&gt;
  
  
  ¿Qué diferencia hay entre un &lt;code&gt;SerialExecutor&lt;/code&gt; y un &lt;code&gt;TaskExecutor&lt;/code&gt;, y para qué sirve cada uno?
&lt;/h3&gt;

&lt;p&gt;Un &lt;code&gt;SerialExecutor&lt;/code&gt; sirve para despachar tareas en un &lt;code&gt;actor&lt;/code&gt;, mientras que un &lt;code&gt;TaskExecutor&lt;/code&gt; sirve para despachar tareas en un &lt;code&gt;Task&lt;/code&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  ¿Por qué es importante que el actor mantenga una referencia fuerte al ejecutor cuando se usa &lt;code&gt;asUnownedSerialExecutor()&lt;/code&gt;?
&lt;/h3&gt;

&lt;p&gt;&lt;code&gt;asUnownedSerialExecutor()&lt;/code&gt; entrega una referencia simple a un objeto en el heap sin conteo de referencias. Por esta razón, si no se retiene la referencia, el objeto se pierde.&lt;/p&gt;

&lt;h3&gt;
  
  
  ¿Cómo funciona el método &lt;code&gt;enqueue(_:)&lt;/code&gt; dentro de un &lt;code&gt;SerialExecutor&lt;/code&gt; basado en &lt;code&gt;DispatchQueue&lt;/code&gt;?
&lt;/h3&gt;

&lt;p&gt;Se despacha una tarea en la cola seria (i.e. &lt;code&gt;dispatchQueue.async&lt;/code&gt;) que consiste en ejecutar síncronamente un &lt;code&gt;UnownedJob&lt;/code&gt; en un &lt;code&gt;SerialExecutor&lt;/code&gt; (i.e. &lt;code&gt;unownedJob.runSynchronously(on: unownedExecutor)&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;final&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="kt"&gt;DispatchQueueExecutor&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;SerialExecutor&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;dispatchQueue&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;DispatchQueue&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;dispatchQueue&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;DispatchQueue&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;dispatchQueue&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;dispatchQueue&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;enqueue&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;_&lt;/span&gt; &lt;span class="nv"&gt;job&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kd"&gt;consuming&lt;/span&gt; &lt;span class="kt"&gt;ExecutorJob&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;unownedJob&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kt"&gt;UnownedJob&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;job&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;unownedExecutor&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;asUnownedSerialExecutor&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

    &lt;span class="n"&gt;dispatchQueue&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;unownedJob&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;runSynchronously&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;on&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;unownedExecutor&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;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;LoggingActor&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;executor&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;DispatchQueueExecutor&lt;/span&gt;
  &lt;span class="kd"&gt;nonisolated&lt;/span&gt; &lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="nv"&gt;unownedExecutor&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;UnownedSerialExecutor&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;executor&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;asUnownedSerialExecutor&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
  &lt;span class="p"&gt;}&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;dispatchQueue&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;DispatchQueue&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;executor&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kt"&gt;DispatchQueueExecutor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;dispatchQueue&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;dispatchQueue&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;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;_&lt;/span&gt; &lt;span class="nv"&gt;message&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="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"[&lt;/span&gt;&lt;span class="se"&gt;\(&lt;/span&gt;&lt;span class="kt"&gt;Thread&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;current&lt;/span&gt;&lt;span class="se"&gt;)&lt;/span&gt;&lt;span class="s"&gt;]: &lt;/span&gt;&lt;span class="se"&gt;\(&lt;/span&gt;&lt;span class="n"&gt;message&lt;/span&gt;&lt;span class="se"&gt;)&lt;/span&gt;&lt;span class="s"&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;h3&gt;
  
  
  ¿Qué métodos permiten configurar una preferencia de ejecutor para tareas &lt;strong&gt;no&lt;/strong&gt; aisladas a un actor?
&lt;/h3&gt;

&lt;p&gt;Primero hay que crear un &lt;code&gt;TaskExecutor&lt;/code&gt;. Notar en el siguiente código cómo se conforma &lt;code&gt;TaskExecutor&lt;/code&gt; y cómo se despacha dentro de la cola serial (i.e. &lt;code&gt;dispatchQueue.async&lt;/code&gt;) una tarea que consiste en ejecutar síncronamente el &lt;code&gt;job&lt;/code&gt; recibido (i.e. &lt;code&gt;unownedJob.runSynchronously(on: unownedExecutor)&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;final&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="kt"&gt;DispatchQueueTaskExecutor&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;TaskExecutor&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;dispatchQueue&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;DispatchQueue&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;dispatchQueue&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;DispatchQueue&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;dispatchQueue&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;dispatchQueue&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;enqueue&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;_&lt;/span&gt; &lt;span class="nv"&gt;job&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kd"&gt;consuming&lt;/span&gt; &lt;span class="kt"&gt;ExecutorJob&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;unownedJob&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kt"&gt;UnownedJob&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;job&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;unownedExecutor&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;asUnownedTaskExecutor&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

    &lt;span class="n"&gt;dispatchQueue&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;unownedJob&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;runSynchronously&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;on&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;unownedExecutor&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;Luego, al definir el &lt;code&gt;Task&lt;/code&gt;, se le pasa el ejecutor preferido:&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;DispatchQueueTaskExecutorTests&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="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;queue&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.logger.queue"&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;taskExecutor&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kt"&gt;DispatchQueueTaskExecutor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;dispatchQueue&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;queue&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="k"&gt;await&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;executorPreference&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;taskExecutor&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="s"&gt;"Task Executor example"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt;

    &lt;span class="cp"&gt;#expect(1 == 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;
  
  
  ¿Qué métodos permiten configurar una preferencia de ejecutor para tareas aisladas a un actor?
&lt;/h3&gt;

&lt;p&gt;Para ejecutar una tarea aislada a un actor se usa &lt;a href="https://developer.apple.com/documentation/swift/executorjob/runsynchronously(isolatedto:taskexecutor:)?changes=latest_beta" rel="noopener noreferrer"&gt;&lt;code&gt;runSynchronously(isolatedTo:taskExecutor:)&lt;/code&gt;&lt;/a&gt; en lugar de &lt;a href="https://developer.apple.com/documentation/swift/executorjob/runsynchronously(on:)-6e565?changes=latest_beta" rel="noopener noreferrer"&gt;&lt;code&gt;runSynchronously(on:)&lt;/code&gt;&lt;/a&gt; como se muestra a continuació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="kd"&gt;final&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="kt"&gt;DispatchQueueTaskExecutor&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;TaskExecutor&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;dispatchQueue&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;DispatchQueue&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;dispatchQueue&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;DispatchQueue&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;dispatchQueue&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;dispatchQueue&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;enqueue&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;_&lt;/span&gt; &lt;span class="nv"&gt;job&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kd"&gt;consuming&lt;/span&gt; &lt;span class="kt"&gt;ExecutorJob&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;unownedJob&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kt"&gt;UnownedJob&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;job&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;unownedExecutor&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;asUnownedTaskExecutor&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

    &lt;span class="n"&gt;dispatchQueue&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;unownedJob&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;runSynchronously&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;isolatedTo&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;DispatchQueueExecutor&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;loggingExecutor&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;asUnownedSerialExecutor&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="nv"&gt;taskExecutor&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="nf"&gt;asUnownedTaskExecutor&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;h3&gt;
  
  
  Mostrar un ejemplo donde se comparta un executor entre actores
&lt;/h3&gt;

&lt;p&gt;Se debe mantener una referencia al executor como si fuera un singleton (e.g. &lt;code&gt;static let loggingExecutor&lt;/code&gt;). Luego, el actor hará referencia a ese singleton desde &lt;code&gt;var unownedExecutor: UnownedSerialExecutor&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;extension&lt;/span&gt; &lt;span class="kt"&gt;DispatchQueueExecutor&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;loggingExecutor&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kt"&gt;DispatchQueueExecutor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="nv"&gt;dispatchQueue&lt;/span&gt;&lt;span class="p"&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.logger.queue"&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;utility&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;actor&lt;/span&gt; &lt;span class="kt"&gt;SharedExecutorLoggingActor&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;nonisolated&lt;/span&gt; &lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="nv"&gt;unownedExecutor&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;UnownedSerialExecutor&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kt"&gt;DispatchQueueExecutor&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;loggingExecutor&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;asUnownedSerialExecutor&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;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;_&lt;/span&gt; &lt;span class="nv"&gt;message&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="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"[&lt;/span&gt;&lt;span class="se"&gt;\(&lt;/span&gt;&lt;span class="kt"&gt;Thread&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;current&lt;/span&gt;&lt;span class="se"&gt;)&lt;/span&gt;&lt;span class="s"&gt;] &lt;/span&gt;&lt;span class="se"&gt;\(&lt;/span&gt;&lt;span class="n"&gt;message&lt;/span&gt;&lt;span class="se"&gt;)&lt;/span&gt;&lt;span class="s"&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;h2&gt;
  
  
  Recordar sin mirar
&lt;/h2&gt;

&lt;h3&gt;
  
  
  ¿Cuál es la diferencia entre compartir un ejecutor entre múltiples actores y que cada actor tenga el suyo propio? ¿Qué implicaciones tiene esto en la concurrencia?
&lt;/h3&gt;

&lt;h3&gt;
  
  
  ¿Qué restricción importante existe al combinar TaskExecutor y SerialExecutor en un mismo tipo?
&lt;/h3&gt;




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

&lt;h3&gt;
  
  
  El artículo describe los ejecutores personalizados como una "solución excepcional". ¿En qué escenarios concretos del desarrollo real estaría justificado usarlos frente al executor por defecto?
&lt;/h3&gt;

&lt;h3&gt;
  
  
  ¿Qué riesgos o errores podrían surgir si se implementa incorrectamente un ejecutor personalizado, por ejemplo usando una cola concurrente donde se requiere una serial?
&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] Herencia de aislamiento de actores mediante el macro #isolation</title>
      <dc:creator>GoyesDev</dc:creator>
      <pubDate>Sat, 25 Apr 2026 13:26:31 +0000</pubDate>
      <link>https://dev.to/david_goyes_a488f58a17a53/sc-herencia-de-aislamiento-de-actores-mediante-el-macro-isolation-1dpe</link>
      <guid>https://dev.to/david_goyes_a488f58a17a53/sc-herencia-de-aislamiento-de-actores-mediante-el-macro-isolation-1dpe</guid>
      <description>&lt;h2&gt;
  
  
  Preguntas
&lt;/h2&gt;

&lt;h3&gt;
  
  
  ¿Qué problema concreto resuelve el macro &lt;code&gt;#isolation&lt;/code&gt; en la concurrencia de Swift?
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://developer.apple.com/documentation/swift/isolation()" rel="noopener noreferrer"&gt;&lt;code&gt;#isolation&lt;/code&gt;&lt;/a&gt; es una ayuda sintáctica (como &lt;code&gt;#file&lt;/code&gt; o &lt;code&gt;#line&lt;/code&gt;) que produce una referencia al actor que aisla el código en cuestión o &lt;code&gt;nil&lt;/code&gt; si el código es &lt;code&gt;nonisolated&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Se usa en conjunto con el modificador de parámetro &lt;code&gt;isolated&lt;/code&gt; que permite ejecutar el código de un método aislado en el actor marcado con &lt;code&gt;isolated&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;#isolation&lt;/code&gt; ayuda a crear código genérico que recibe un parámetro &lt;code&gt;isolated&lt;/code&gt; y se le pasa por defecto una referencia al actor que invocó dicho código.&lt;/p&gt;

&lt;h3&gt;
  
  
  ¿Por qué las funciones asíncronas normalmente "rompen" el aislamiento del actor llamador?
&lt;/h3&gt;

&lt;p&gt;Generalmente las funciones asíncronas son &lt;code&gt;non-isolated&lt;/code&gt;, provocando posibles puntos de suspensión innecesarios y limitando la capacidad del código de trabajar con datos no-&lt;code&gt;Sendable&lt;/code&gt; dentro del contexto de un actor.&lt;/p&gt;

&lt;h3&gt;
  
  
  ¿En qué situaciones sería útil heredar el aislamiento del actor en lugar de usar &lt;code&gt;@MainActor&lt;/code&gt; directamente?
&lt;/h3&gt;

&lt;p&gt;Usar directamente &lt;code&gt;@MainActor&lt;/code&gt; implica asumir que el código invocador también se ejecuta en &lt;code&gt;MainActor&lt;/code&gt;. Lo ideal es no asumir esto y, en su lugar, mejor heredar el contexto de aislamiento del invocador.&lt;/p&gt;

&lt;h3&gt;
  
  
  Según el artículo, ¿cómo funciona el macro &lt;code&gt;#isolation&lt;/code&gt; como argumento por defecto en un parámetro &lt;code&gt;isolated&lt;/code&gt;?
&lt;/h3&gt;

&lt;p&gt;&lt;code&gt;#isolation&lt;/code&gt; devuelve una referencia al actor invocador o &lt;code&gt;nil&lt;/code&gt; si se invocó desde &lt;code&gt;nonisolated&lt;/code&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  ¿Por qué el compilador se queja cuando &lt;code&gt;sequentialMap&lt;/code&gt; llama al closure &lt;code&gt;transform&lt;/code&gt; sin usar &lt;code&gt;#isolation&lt;/code&gt;?
&lt;/h3&gt;

&lt;p&gt;El closure &lt;code&gt;transform&lt;/code&gt;, en Swift 6.0, es de tipo &lt;code&gt;nonisolated(nonsending)&lt;/code&gt; y el método &lt;code&gt;sequentialMap&lt;/code&gt; originalmente es &lt;code&gt;nonisolated&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Invocar &lt;code&gt;sequentialMap&lt;/code&gt; desde &lt;code&gt;@MainActor&lt;/code&gt; implica usar un &lt;code&gt;await&lt;/code&gt; porque se va a salir del dominio &lt;code&gt;MainActor&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;El closure que se pasa a &lt;code&gt;transform&lt;/code&gt; está aislado en &lt;code&gt;MainActor&lt;/code&gt; y usa valores de ese dominio (porque la colección &lt;code&gt;names&lt;/code&gt; se definió en &lt;code&gt;MainActor&lt;/code&gt; y, por ende, los valores de tipo &lt;code&gt;Element&lt;/code&gt; están en ese actor - Aunque particularmente en este ejemplo, &lt;code&gt;String&lt;/code&gt; es &lt;code&gt;Sendable&lt;/code&gt;). Además, el closure captura el contexto de &lt;code&gt;@MainActor&lt;/code&gt;, y al ser &lt;code&gt;nonisolated(nonsending)&lt;/code&gt; no puede cruzar hacia el dominio &lt;code&gt;nonisolated&lt;/code&gt; de &lt;code&gt;sequentialMap&lt;/code&gt; de forma segura.&lt;/p&gt;

&lt;p&gt;Entonces, parte de &lt;code&gt;MainActor&lt;/code&gt;, sale a &lt;code&gt;nonisolated&lt;/code&gt;, pero trae contexto del dominio de &lt;code&gt;MainActor&lt;/code&gt; que no puede cruzar de forma segura (por ser &lt;code&gt;nonsending&lt;/code&gt;). Por esta razón se explota.&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;extension&lt;/span&gt; &lt;span class="kt"&gt;Collection&lt;/span&gt; &lt;span class="k"&gt;where&lt;/span&gt; &lt;span class="kt"&gt;Element&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;nonisolated&lt;/span&gt; &lt;span class="kd"&gt;func&lt;/span&gt; &lt;span class="n"&gt;sequentialMap&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;Result&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;Sendable&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&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="kt"&gt;Element&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;Result&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="p"&gt;[&lt;/span&gt;&lt;span class="kt"&gt;Result&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;results&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="kt"&gt;Result&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="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;element&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="k"&gt;self&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="n"&gt;results&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="k"&gt;await&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;element&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;results&lt;/span&gt;
  &lt;span class="p"&gt;}&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;Test&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="kt"&gt;Task&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="kd"&gt;@MainActor&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt;
      &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;names&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;"Antoine"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"Maaike"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"Sep"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"Jip"&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;lowercaseNames&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;names&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;sequentialMap&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt;
        &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;lowercaseWithSleep&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;input&lt;/span&gt;&lt;span class="p"&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="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;lowercaseNames&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;@MainActor&lt;/span&gt; 
  &lt;span class="kd"&gt;func&lt;/span&gt; &lt;span class="nf"&gt;lowercaseWithSleep&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;input&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;async&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="n"&gt;input&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;lowercased&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 la solución, en lugar de que el método &lt;code&gt;sequentialMap&lt;/code&gt; sea &lt;code&gt;nonisolated&lt;/code&gt;, y que &lt;code&gt;transform&lt;/code&gt; sea &lt;code&gt;nonisolated(nonsending)&lt;/code&gt;, se hereda el dominio del actor invocador con &lt;code&gt;isolated&lt;/code&gt; y se pasa por defecto &lt;code&gt;#isolation&lt;/code&gt;. Esto provoca que el closure &lt;code&gt;tranform&lt;/code&gt; se ejecute en el dominio de aislamiento de &lt;code&gt;isolated&lt;/code&gt; y resuelve el error.&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;extension&lt;/span&gt; &lt;span class="kt"&gt;Collection&lt;/span&gt; &lt;span class="k"&gt;where&lt;/span&gt; &lt;span class="kt"&gt;Element&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;func&lt;/span&gt; &lt;span class="n"&gt;sequentialMap&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;Result&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;Sendable&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="nv"&gt;isolation&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;isolated&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;any&lt;/span&gt; &lt;span class="kt"&gt;Actor&lt;/span&gt;&lt;span class="p"&gt;)?&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;#isolation&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="kt"&gt;Element&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;Result&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="p"&gt;[&lt;/span&gt;&lt;span class="kt"&gt;Result&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;results&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="kt"&gt;Result&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="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;element&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="k"&gt;self&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="n"&gt;results&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="k"&gt;await&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;element&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;results&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é cambio específico en la firma de la función resuelve el problema de las data races?
&lt;/h3&gt;

&lt;p&gt;&lt;code&gt;isolation: isolated (any Actor)? = #isolation&lt;/code&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  ¿Cuáles son los tres beneficios de rendimiento y seguridad que menciona el artículo al usar herencia de aislamiento?
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Evita usar suspensiones innecesarias.&lt;/li&gt;
&lt;li&gt;Permite pasar valores no-&lt;code&gt;Sendable&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Evita detrimento en el rendimiento al cambiar de contextos. &lt;/li&gt;
&lt;/ul&gt;




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

&lt;h3&gt;
  
  
  Sin mirar el código, ¿puedes describir cómo quedaría la firma completa de &lt;code&gt;sequentialMap&lt;/code&gt; usando &lt;code&gt;#isolation&lt;/code&gt;?
&lt;/h3&gt;

&lt;h3&gt;
  
  
  Explica con tus propias palabras la diferencia entre una función aislada en un actor y una función &lt;code&gt;non-isolated&lt;/code&gt;.
&lt;/h3&gt;

&lt;h3&gt;
  
  
  ¿Por qué no era suficiente marcar &lt;code&gt;sequentialMap&lt;/code&gt; directamente con &lt;code&gt;@MainActor&lt;/code&gt; para resolver el problema del ejemplo?
&lt;/h3&gt;




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

&lt;h3&gt;
  
  
  ¿En qué tipos de proyectos o situaciones reales aplicarías el macro &lt;code&gt;#isolation&lt;/code&gt;? ¿Por qué el artículo advierte que no es para todos los proyectos?
&lt;/h3&gt;

&lt;h3&gt;
  
  
  ¿Cómo se relaciona la herencia de aislamiento de actores con el concepto de "cambio de contexto" (context switching) y el rendimiento de la app?
&lt;/h3&gt;

&lt;h3&gt;
  
  
  ¿Qué pregunta o concepto del artículo quedó menos claro y cómo podrías investigarlo más?
&lt;/h3&gt;




&lt;h2&gt;
  
  
  Nota
&lt;/h2&gt;

&lt;p&gt;Al hacer los experimentos del código en Xcode 26.4 pude notar que los errores descritos por el artículo no salían. Esto se debe a que tenía marcada la opción por defecto &lt;code&gt;SWIFT_APPROACHABLE_CONCURRENCY = YES&lt;/code&gt; que habilita la funcionalidad &lt;code&gt;NonisolatedNonsendingByDefault&lt;/code&gt; de Swift 6.2 que cambia cómo funcionan los closures &lt;code&gt;nonisolated async&lt;/code&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;En Swift 6.0 el closure &lt;code&gt;transform&lt;/code&gt; es &lt;code&gt;nonisolated&lt;/code&gt; y &lt;code&gt;Sendable&lt;/code&gt;, lo que le permite cruzar hacia el contexto &lt;code&gt;nonisolated&lt;/code&gt; de &lt;code&gt;sequentialMap&lt;/code&gt; llevando valores del &lt;code&gt;@MainActor&lt;/code&gt; — de ahí la carrera de datos y el error del compilador.&lt;/li&gt;
&lt;li&gt;En Swift 6.2, el closure transform se vuelve implícitamente &lt;code&gt;nonisolated(nonsending)&lt;/code&gt;, lo que impide que cruce fronteras de concurrencia de forma insegura. Por eso el compilador ya no reporta el error.&lt;/li&gt;
&lt;li&gt;El macro &lt;code&gt;#isolation&lt;/code&gt; era la solución manual a este problema en Swift 6.0, que Swift 6.2 resuelve automáticamente con &lt;code&gt;NonisolatedNonsendingByDefault&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Según el razonamiento anterior, podría pensar que marcar con &lt;code&gt;nonisolated(nonsending)&lt;/code&gt; al closure &lt;code&gt;transform&lt;/code&gt; bastaría para que no salga el error, sin embargo, esto no es así. &lt;/p&gt;

&lt;p&gt;&lt;code&gt;nonisolated(nonsending)&lt;/code&gt; le dice al compilador: "este closure no puede cruzar fronteras", pero &lt;code&gt;sequentialMap&lt;/code&gt; sigue siendo &lt;code&gt;nonisolated&lt;/code&gt;. Por esta razón, el compilador detecta que estoy mandando el closure a otro dominio y reporta el error. Por esta razón, es necesario poner el parámetro &lt;code&gt;isolation: isolated (any Actor)? = #isolation&lt;/code&gt;, lo que le permite al compilador deducir el actor que aisla al método &lt;code&gt;sequentialMap&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Cuando Swift 6.2 aplica &lt;code&gt;nonisolated(nonsending)&lt;/code&gt; automáticamente con &lt;code&gt;SWIFT_APPROACHABLE_CONCURRENCY = YES&lt;/code&gt; también ajusta cómo el compilador razona sobre el sitio de llamada: &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;El compilador ya sabe que el closure es &lt;code&gt;nonisolated(nonsending)&lt;/code&gt; y, en lugar de tratarlo como un valor que se envía a &lt;code&gt;sequentialMap&lt;/code&gt;, lo trata como un valor que permanece en el dominio del llamador (@MainActor) durante toda la ejecución. Así se cumple la restricción del closure sin necesidad de anclar la función con &lt;code&gt;#isolation&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&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>ios</category>
      <category>swift</category>
      <category>swiftconcurrency</category>
      <category>concurrency</category>
    </item>
    <item>
      <title>[SC] Reentrada de actores</title>
      <dc:creator>GoyesDev</dc:creator>
      <pubDate>Fri, 24 Apr 2026 22:58:41 +0000</pubDate>
      <link>https://dev.to/david_goyes_a488f58a17a53/sc-reentrada-de-actores-29mf</link>
      <guid>https://dev.to/david_goyes_a488f58a17a53/sc-reentrada-de-actores-29mf</guid>
      <description>&lt;h2&gt;
  
  
  Preguntas
&lt;/h2&gt;

&lt;h3&gt;
  
  
  ¿Qué significa exactamente la "reentrada de un actor" (&lt;em&gt;actor reentrancy&lt;/em&gt;)?
&lt;/h3&gt;

&lt;p&gt;Al usar &lt;code&gt;await&lt;/code&gt; dentro de un actor, otra tarea potencialmente puede ser ejecutada mientras que la primera está suspendida.&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;Player&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="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"Anonymous"&lt;/span&gt;
  &lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="nv"&gt;score&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;addToScore&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="n"&gt;score&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;try&lt;/span&gt;&lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="kt"&gt;Task&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;sleep&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;for&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;seconds&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="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Score is now &lt;/span&gt;&lt;span class="se"&gt;\(&lt;/span&gt;&lt;span class="n"&gt;score&lt;/span&gt;&lt;span class="se"&gt;)&lt;/span&gt;&lt;span class="s"&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="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;player&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kt"&gt;Player&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;player&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;addToScore&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;player&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;addToScore&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;player&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;addToScore&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

&lt;span class="k"&gt;try&lt;/span&gt;&lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="kt"&gt;Task&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;sleep&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;for&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;seconds&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mf"&gt;1.1&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, cada vez que el &lt;code&gt;Task&lt;/code&gt; del actor se suspende en &lt;code&gt;await Task.sleep(for: .seconds(1))&lt;/code&gt; permite que actor ejecute cualquier otra tarea. A esto se le conoce como "interleaving".&lt;/p&gt;

&lt;p&gt;"Actor reentrancy" es el fenómeno que se produce cuando, debido al interleaving, una tarea modifica de forma inesperada el estado que estaba usando otra tarea.&lt;/p&gt;

&lt;p&gt;El problema se resume en que el estado del actor puede cambiar entre dos líneas si hay un &lt;code&gt;await&lt;/code&gt; de por medio.&lt;/p&gt;

&lt;h3&gt;
  
  
  ¿Por qué salir temporalmente de un actor puede causar comportamiento inesperado?
&lt;/h3&gt;

&lt;p&gt;Cuando se sale del actor y se vuelve a entrar, es posible el estado ya haya cambiado. Por esta razón, antes de salir del dominio del actor, hay que procurar terminar las operaciones que cambian el estado.&lt;/p&gt;

&lt;h3&gt;
  
  
  ¿Qué condición permite que otras tareas "entren" al actor mientras este está suspendido?
&lt;/h3&gt;

&lt;p&gt;Un punto de suspensión.&lt;/p&gt;

&lt;h3&gt;
  
  
  ¿Cómo afecta el uso de &lt;code&gt;await&lt;/code&gt; al flujo de ejecución dentro de un actor?
&lt;/h3&gt;

&lt;p&gt;El método se suspende, y el actor permite que otra tarea se ejecute mientras tanto.&lt;/p&gt;

&lt;h3&gt;
  
  
  En el ejemplo del &lt;code&gt;BankAccount&lt;/code&gt;, ¿por qué el saldo impreso es 250.0 tres veces en lugar de 150.0, 200.0 y 250.0?
&lt;/h3&gt;

&lt;p&gt;Las tres invocaciones al depósito salían a hacer un &lt;code&gt;sleep&lt;/code&gt;. Las tres tareas modificaron el estado del &lt;code&gt;BankAccount&lt;/code&gt;, pero después de salir del actor, volvían a depender de ese estado, por lo que las tres tareas reflejaron el estado final después de la última ejecución.&lt;/p&gt;

&lt;h3&gt;
  
  
  ¿Qué papel cumple el &lt;code&gt;BankAccountActivityLogger&lt;/code&gt; en el bug descrito?
&lt;/h3&gt;

&lt;p&gt;Hace un &lt;code&gt;Task.sleep&lt;/code&gt; que demora la ejecución, además, es otro dominio de aislamiento diferente, lo que ilustra el cambio entre dominios. Sin embargo, el problema también se presenta incluso aunque no se salga del dominio de un actor como se mostró en &lt;code&gt;Player&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;BankAccount&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;balance&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;Double&lt;/span&gt;
  &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;activityLogger&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kt"&gt;BankAccountActivityLogger&lt;/span&gt;&lt;span class="p"&gt;()&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;initialDeposit&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;Double&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;balance&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;initialDeposit&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;Double&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="n"&gt;balance&lt;/span&gt; &lt;span class="o"&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="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;activityLogger&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;BankAccountActivity&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;activity&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;"Increased balance by &lt;/span&gt;&lt;span class="se"&gt;\(&lt;/span&gt;&lt;span class="n"&gt;amount&lt;/span&gt;&lt;span class="se"&gt;)&lt;/span&gt;&lt;span class="s"&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="s"&gt;"Balance is now &lt;/span&gt;&lt;span class="se"&gt;\(&lt;/span&gt;&lt;span class="n"&gt;balance&lt;/span&gt;&lt;span class="se"&gt;)&lt;/span&gt;&lt;span class="s"&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="kd"&gt;struct&lt;/span&gt; &lt;span class="kt"&gt;BankAccountActivity&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;date&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;Date&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;now&lt;/span&gt;
  &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;activity&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="kd"&gt;actor&lt;/span&gt; &lt;span class="kt"&gt;BankAccountActivityLogger&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;activities&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="kt"&gt;BankAccountActivity&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;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;_&lt;/span&gt; &lt;span class="nv"&gt;activity&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;BankAccountActivity&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="n"&gt;activities&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;activity&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="c1"&gt;/// Se agrega un sleep para simular la sincronización remota de la actividad.&lt;/span&gt;
    &lt;span class="k"&gt;try&lt;/span&gt;&lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="kt"&gt;Task&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;sleep&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;for&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;seconds&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="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;
  
  
  ¿Por qué el &lt;code&gt;Task.sleep&lt;/code&gt; dentro del &lt;code&gt;logger&lt;/code&gt; es relevante para reproducir el problema?
&lt;/h3&gt;

&lt;p&gt;Provoca suficiente retraso como para que otra tarea del actor pueda provocar cambios.&lt;/p&gt;




&lt;h2&gt;
  
  
  Recordar
&lt;/h2&gt;

&lt;h3&gt;
  
  
  ¿Cuál fue la solución propuesta para corregir el bug de reentrada en el método &lt;code&gt;deposit&lt;/code&gt;?
&lt;/h3&gt;

&lt;h3&gt;
  
  
  En tus propias palabras, ¿cuál es la regla general que se debe seguir antes de salir del dominio de aislamiento de un actor?
&lt;/h3&gt;




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

&lt;h3&gt;
  
  
  ¿En qué tipos de situaciones reales podría aparecer un bug de &lt;em&gt;actor reentrancy&lt;/em&gt; fuera de este ejemplo?
&lt;/h3&gt;

&lt;h3&gt;
  
  
  ¿Por qué el artículo dice que este es un problema "caso por caso" sin una solución universal?
&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>
  </channel>
</rss>
