<?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] Migrando a Notificaciones seguras (en términos de concurrencia)</title>
      <dc:creator>GoyesDev</dc:creator>
      <pubDate>Mon, 25 May 2026 22:21:05 +0000</pubDate>
      <link>https://dev.to/david_goyes_a488f58a17a53/sc-agj</link>
      <guid>https://dev.to/david_goyes_a488f58a17a53/sc-agj</guid>
      <description>&lt;h2&gt;
  
  
  Comprensión durante la lectura
&lt;/h2&gt;

&lt;h3&gt;
  
  
  ¿Por qué las notificaciones estándar de &lt;code&gt;NotificationCenter&lt;/code&gt; no son thread-safe en Swift Concurrency?
&lt;/h3&gt;

&lt;p&gt;Porque el tipo &lt;code&gt;Notification&lt;/code&gt; es &lt;code&gt;nonisolated&lt;/code&gt; por defecto, incluso cuando se publica desde un actor conocido como el &lt;code&gt;MainActor&lt;/code&gt;. Esto impide que el compilador razone sobre la seguridad de hilos al llamar métodos con aislamiento específico como &lt;code&gt;@MainActor&lt;/code&gt;, incluso aunque recibamos la notificación en el hilo principal.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight swift"&gt;&lt;code&gt;&lt;span class="kd"&gt;func&lt;/span&gt; &lt;span class="nf"&gt;startObservingOldWay&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kt"&gt;NotificationCenter&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="k"&gt;default&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;addObserver&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;forName&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;UIApplication&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;didBecomeActiveNotification&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;object&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;nil&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;queue&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;main&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;using&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;weak&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;notification&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="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;handleDidBecomeActive&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;handleDidBecomeActive&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;"Did become active!"&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é problema concreto resuelve &lt;code&gt;MainActorMessage&lt;/code&gt; frente al API anterior?
&lt;/h3&gt;

&lt;p&gt;Garantiza que el closure de observación se ejecute en el main actor, eliminando la advertencia de concurrencia y permitiendo llamar directamente a métodos &lt;code&gt;@MainActor&lt;/code&gt; sin conversiones manuales.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight swift"&gt;&lt;code&gt;&lt;span class="kd"&gt;func&lt;/span&gt; &lt;span class="nf"&gt;startObservingNewWay&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="n"&gt;token&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kt"&gt;NotificationCenter&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="k"&gt;default&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;addObserver&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;of&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;UIApplication&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="k"&gt;self&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="n"&gt;didBecomeActive&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;weak&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;message&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="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;handleDidBecomeActive&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;handleDidBecomeActive&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;"Did become active!"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  ¿Cuál es la diferencia clave entre &lt;code&gt;MainActorMessage&lt;/code&gt; y &lt;code&gt;AsyncMessage&lt;/code&gt;?
&lt;/h3&gt;

&lt;p&gt;&lt;code&gt;MainActorMessage&lt;/code&gt; entrega la notificación sincrónicamente en el main actor. &lt;code&gt;AsyncMessage&lt;/code&gt; la entrega de forma asíncrona en un aislamiento arbitrario y puede publicarse desde cualquier dominio de aislamiento.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight swift"&gt;&lt;code&gt;&lt;span class="kd"&gt;struct&lt;/span&gt; &lt;span class="kt"&gt;RecentBuildsChangedMessage&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;NotificationCenter&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="kt"&gt;AsyncMessage&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;typealias&lt;/span&gt; &lt;span class="kt"&gt;Subject&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="kt"&gt;RecentBuild&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;recentBuilds&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;Subject&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;extension&lt;/span&gt; &lt;span class="kt"&gt;NotificationCenter&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="kt"&gt;MessageIdentifier&lt;/span&gt; &lt;span class="k"&gt;where&lt;/span&gt; &lt;span class="k"&gt;Self&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="kt"&gt;NotificationCenter&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="kt"&gt;BaseMessageIdentifier&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;RecentBuildsChangedMessage&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="nv"&gt;recentBuildsChanged&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;NotificationCenter&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="kt"&gt;BaseMessageIdentifier&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;RecentBuildsChangedMessage&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;init&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight swift"&gt;&lt;code&gt;&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;recentBuilds&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="kt"&gt;RecentBuild&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;appName&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;"Stock Analyzer"&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;message&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kt"&gt;RecentBuildsChangedMessage&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;recentBuilds&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;recentBuilds&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="kt"&gt;NotificationCenter&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="k"&gt;default&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;post&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;message&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="n"&gt;recentBuildsToken&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kt"&gt;NotificationCenter&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="k"&gt;default&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;addObserver&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;of&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="kt"&gt;RecentBuild&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="k"&gt;self&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="n"&gt;recentBuildsChanged&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;weak&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;message&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="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;handleNewRecentBuilds&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;message&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;recentBuilds&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é ventajas concretas aporta migrar a notificaciones con tipo fuerte (strongly typed)?
&lt;/h3&gt;

&lt;p&gt;Se elimina la necesidad de hacer casting manual desde &lt;code&gt;notification.object as? [RecentBuild]&lt;/code&gt;, se reduce el boilerplate y se obtiene verificación en tiempo de compilación, además de la seguridad de hilos.&lt;/p&gt;

&lt;h3&gt;
  
  
  ¿Qué cambio de comportamiento en threading puede ocurrir al migrar al nuevo API?
&lt;/h3&gt;

&lt;p&gt;En el API anterior las notificaciones se entregaban en la misma cola desde la que se publicaban. Con el nuevo API, el &lt;code&gt;@MainActor&lt;/code&gt; se aplica más estrictamente, lo que puede cambiar el comportamiento de threading de la app tras la migración.&lt;/p&gt;




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

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

</description>
      <category>swift</category>
      <category>ios</category>
      <category>concurrency</category>
      <category>swiftconcurrency</category>
    </item>
    <item>
      <title>[SC] Migrando desde programación reactiva (RxSwift y Combine)</title>
      <dc:creator>GoyesDev</dc:creator>
      <pubDate>Mon, 25 May 2026 22:01:50 +0000</pubDate>
      <link>https://dev.to/david_goyes_a488f58a17a53/sc-migrando-desde-programacion-reactiva-rxswift-y-combine-49mj</link>
      <guid>https://dev.to/david_goyes_a488f58a17a53/sc-migrando-desde-programacion-reactiva-rxswift-y-combine-49mj</guid>
      <description>&lt;h2&gt;
  
  
  Comprensión durante la lectura
&lt;/h2&gt;

&lt;h3&gt;
  
  
  ¿Por qué la comunidad Swift está migrando de RxSwift y Combine?
&lt;/h3&gt;

&lt;p&gt;&lt;code&gt;Combine&lt;/code&gt; está recibiendo menos actualizaciones y la comunidad de programación reactiva está perdiendo popularidad.&lt;/p&gt;

&lt;h3&gt;
  
  
  ¿Existe alguna alternativa nativa en Swift 6 para la observación reactiva de valores?
&lt;/h3&gt;

&lt;p&gt;Existe una propuesta en curso &lt;a href="https://github.com/swiftlang/swift-evolution/blob/main/proposals/0475-observed.md" rel="noopener noreferrer"&gt;SE-475 Transactional Observation of Values&lt;/a&gt; que técnicamente permite observar cambios sobre un atributo y procesarlos como si fuera un &lt;code&gt;AsyncSequence&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="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="kt"&gt;Observations&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;person&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kt"&gt;Task&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;detached&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="n"&gt;names&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;"Name 1 was updated to: &lt;/span&gt;&lt;span class="se"&gt;\(&lt;/span&gt;&lt;span class="n"&gt;name&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="kt"&gt;Task&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;detached&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="n"&gt;names&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;"Name 2 was updated to: &lt;/span&gt;&lt;span class="se"&gt;\(&lt;/span&gt;&lt;span class="n"&gt;name&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;
  
  
  ¿Cómo se implementa el debouncing sin Combine?
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight swift"&gt;&lt;code&gt;&lt;span class="n"&gt;$searchQuery&lt;/span&gt;
  &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;debounce&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;milliseconds&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;500&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="nv"&gt;scheduler&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;DispatchQueue&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;main&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;sink&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;receiveValue&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;weak&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;query&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt;
    &lt;span class="k"&gt;guard&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="n"&gt;query&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;isEmpty&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="p"&gt;?&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;searchResults&lt;/span&gt; &lt;span class="o"&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;articleTitlesDatabase&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="c1"&gt;/// A simplified static result and search implementation.&lt;/span&gt;
  &lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="p"&gt;?&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;searchResults&lt;/span&gt; &lt;span class="o"&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;articleTitlesDatabase&lt;/span&gt;
    &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;filter&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nv"&gt;$0&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="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;contains&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;query&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;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;store&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;in&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;cancellables&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 funciona el reemplazo de un pipeline de &lt;code&gt;debounce&lt;/code&gt; usando &lt;code&gt;Task.sleep&lt;/code&gt; y cancelación manual?
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight swift"&gt;&lt;code&gt;&lt;span class="c1"&gt;/// Using manual cancellation management.&lt;/span&gt;
&lt;span class="kd"&gt;func&lt;/span&gt; &lt;span class="nf"&gt;search&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="c1"&gt;/// Cancel any previous searches that might be 'sleeping'.&lt;/span&gt;
  &lt;span class="n"&gt;currentSearchTask&lt;/span&gt;&lt;span class="p"&gt;?&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;cancel&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

  &lt;span class="n"&gt;currentSearchTask&lt;/span&gt; &lt;span class="o"&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;do&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="c1"&gt;/// Debounce for 0.5 seconds to wait for a pause in typing before executing the search.&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;milliseconds&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;500&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;"Starting to search!"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

      &lt;span class="k"&gt;guard&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="n"&gt;query&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;isEmpty&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;searchResults&lt;/span&gt; &lt;span class="o"&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;articleTitlesDatabase&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt;

      &lt;span class="c1"&gt;/// A simplified static result and search implementation.&lt;/span&gt;
      &lt;span class="n"&gt;searchResults&lt;/span&gt; &lt;span class="o"&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;articleTitlesDatabase&lt;/span&gt;
        &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;filter&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nv"&gt;$0&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="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;contains&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;query&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;span class="k"&gt;catch&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;"Search was cancelled!"&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;
  
  
  Problema con el &lt;code&gt;NotificationCenter&lt;/code&gt;
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight swift"&gt;&lt;code&gt;&lt;span class="kt"&gt;NotificationCenter&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="k"&gt;default&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;publisher&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="n"&gt;someNotification&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;sink&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="k"&gt;weak&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;_&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="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;didReceiveSomeNotification&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="nf"&gt;store&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;in&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;cancellables&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;Notifications today rely on an implicit contract that an observer’s code block will run on the same thread as the poster, requiring the client to look up concurrency contracts in documentation, or defensively apply concurrency mechanisms which may or may not lead to issues. Notifications do allow the observer to specify an OperationQueue to execute on, but this concurrency model does not provide compile-time checking and may not be desirable to clients using Swift Concurrency.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Se espera que el observador del &lt;code&gt;NotificationCenter&lt;/code&gt; corra en el mismo hilo que emite la notificación.&lt;/p&gt;

&lt;h3&gt;
  
  
  ¿Por qué los closures de &lt;code&gt;sink&lt;/code&gt; no ofrecen seguridad en tiempo de compilación con actores?
&lt;/h3&gt;

&lt;p&gt;Combine no está integrado con el sistema de concurrencia de Swift 6, por lo que el compilador no puede verificar si el código dentro de un &lt;code&gt;sink&lt;/code&gt; es seguro respecto al aislamiento de actores.&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="kt"&gt;NotificationCenter&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="k"&gt;default&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;publisher&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="n"&gt;someNotification&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;sink&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="k"&gt;weak&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;_&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="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;didReceiveSomeNotification&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="c1"&gt;// ✅ Compila sin errores... pero puede crashear&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;store&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;in&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;cancellables&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;// ❌ El compilador advierte que esto es inseguro&lt;/span&gt;
&lt;span class="kt"&gt;NotificationCenter&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="k"&gt;default&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;addObserver&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;El closure de &lt;code&gt;sink&lt;/code&gt; es esencialmente una caja negra para el compilador en términos de concurrencia. Swift no sabe en qué hilo se va a ejecutar ese closure, por lo que no puede garantizar que respete el aislamiento del &lt;code&gt;@MainActor&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;El riesgo concreto es el siguiente: si una notificación es enviada desde un &lt;code&gt;Task.detached&lt;/code&gt; (fuera del hilo principal), el closure de &lt;code&gt;sink&lt;/code&gt; se ejecutará en ese mismo hilo, violando el aislamiento del actor y produciendo un crash en tiempo de ejecución, no un error en tiempo de compilación.&lt;/p&gt;




&lt;h2&gt;
  
  
  Recordar sin releer
&lt;/h2&gt;

&lt;h3&gt;
  
  
  ¿Cuál es el riesgo de threading cuando se usa &lt;code&gt;sink&lt;/code&gt; junto con actores de Swift Concurrency?
&lt;/h3&gt;

&lt;h3&gt;
  
  
  ¿Por qué &lt;code&gt;receive(on:)&lt;/code&gt; no es suficiente para resolver problemas de aislamiento de actores?
&lt;/h3&gt;

&lt;h3&gt;
  
  
  ¿Cuándo tiene sentido quedarse con Combine en lugar de migrar?
&lt;/h3&gt;




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

&lt;h3&gt;
  
  
  ¿Cuáles son las dos soluciones propuestas para manejar &lt;code&gt;NotificationCenter&lt;/code&gt; con actores?
&lt;/h3&gt;

&lt;h3&gt;
  
  
  ¿Qué ventaja concreta ofrece reescribir código en Swift Concurrency respecto a la seguridad en tiempo de compilación?
&lt;/h3&gt;

&lt;h3&gt;
  
  
  En tu opinión, ¿los argumentos del autor son suficientes para justificar una migración completa en un proyecto grande?
&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>swiftconcurency</category>
    </item>
    <item>
      <title>[SC] ¿Cuándo y cómo usar @preconcurrency ?</title>
      <dc:creator>GoyesDev</dc:creator>
      <pubDate>Mon, 25 May 2026 20:59:48 +0000</pubDate>
      <link>https://dev.to/david_goyes_a488f58a17a53/sc-cuando-y-como-usar-preconcurrency--21ac</link>
      <guid>https://dev.to/david_goyes_a488f58a17a53/sc-cuando-y-como-usar-preconcurrency--21ac</guid>
      <description>&lt;h2&gt;
  
  
  Comprensión durante la lectura
&lt;/h2&gt;

&lt;h3&gt;
  
  
  ¿Qué es el atributo &lt;code&gt;@preconcurrency&lt;/code&gt; y para qué sirve?
&lt;/h3&gt;

&lt;p&gt;El atributo &lt;code&gt;@preconcurrency&lt;/code&gt; permite silenciar los warnings de concurrencia relacionados con conformar el protocolo &lt;code&gt;Sendable&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;La idea es que hay dependencias de terceros que están fuera de nuestro control y no podemos modificar. Por esta razón, podemos importar dichas dependencias así:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight swift"&gt;&lt;code&gt;&lt;span class="kd"&gt;@preconcurrency&lt;/span&gt; &lt;span class="kd"&gt;import&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;some_module&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  ¿En qué se diferencia &lt;code&gt;@preconcurrency&lt;/code&gt; de &lt;code&gt;@unchecked Sendable&lt;/code&gt;?
&lt;/h3&gt;

&lt;p&gt;&lt;code&gt;@unchecked Sendable&lt;/code&gt; sirve para indicar que el tipo marcado &lt;strong&gt;ES&lt;/strong&gt; &lt;code&gt;Sendable&lt;/code&gt;, y que nosotros vamos a asegurarlo manualmente. El compilador no necesita revisar.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;@preconcurrency&lt;/code&gt; sirve solo para silenciar las advertencias de la dependencia importada. Esto no necesariamente significa que dicha dependencia sea segura para concurrencia.&lt;/p&gt;

&lt;h3&gt;
  
  
  ¿Qué riesgos conlleva suprimir las advertencias de concurrencia con este atributo?
&lt;/h3&gt;

&lt;p&gt;Se puede ocultar una vulnerabilidad importante relacionada con el manejo de varios hilos en la biblioteca de terceros.&lt;/p&gt;

&lt;h3&gt;
  
  
  ¿Qué sucede con las importaciones &lt;code&gt;@preconcurrency&lt;/code&gt; al migrar a Swift 6?
&lt;/h3&gt;

&lt;p&gt;Si una dependencia de tercero importada con &lt;code&gt;@preconcurrency&lt;/code&gt; se actualiza y ya no presenta advertencias de tipo &lt;code&gt;@preconcurrency&lt;/code&gt;, entonces resultará en un error de compilación una vez se use Swift 6.&lt;/p&gt;




&lt;h2&gt;
  
  
  Recordar sin releer
&lt;/h2&gt;

&lt;h3&gt;
  
  
  ¿Puedes explicar con tus propias palabras cuándo tiene sentido usar &lt;code&gt;@preconcurrency&lt;/code&gt; y cuándo no?
&lt;/h3&gt;

&lt;h3&gt;
  
  
  ¿Qué pasos debería seguir un equipo que usa &lt;code&gt;@preconcurrency&lt;/code&gt; para no olvidarse de ese código en el futuro?
&lt;/h3&gt;




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

&lt;h3&gt;
  
  
  ¿Cuál es la alternativa preferible a usar &lt;code&gt;@preconcurrency&lt;/code&gt; según el artículo, y por qué?
&lt;/h3&gt;

&lt;h3&gt;
  
  
  ¿Qué estrategia recomienda el autor para gestionar las importaciones marcadas con &lt;code&gt;@preconcurrency&lt;/code&gt; a largo plazo?
&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] Técnicas para reescribir closures en código async/await</title>
      <dc:creator>GoyesDev</dc:creator>
      <pubDate>Mon, 25 May 2026 20:46:19 +0000</pubDate>
      <link>https://dev.to/david_goyes_a488f58a17a53/sc-tecnicas-para-reescribir-closures-en-codigo-asyncawait-11pn</link>
      <guid>https://dev.to/david_goyes_a488f58a17a53/sc-tecnicas-para-reescribir-closures-en-codigo-asyncawait-11pn</guid>
      <description>&lt;h2&gt;
  
  
  Comprensión durante la lectura
&lt;/h2&gt;

&lt;h3&gt;
  
  
  ¿Qué problema resuelve migrar de closures a &lt;code&gt;async/await&lt;/code&gt;, y por qué se describe el problema anterior como "Closure-hell"?
&lt;/h3&gt;

&lt;p&gt;El uso de closures puede ser peligroso porque:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;el desarrollador puede olvidar invocar el closure para devolver el resultado.&lt;/li&gt;
&lt;li&gt;Puede haber varios closures anidados lo que dificulta el mantenimiento&lt;/li&gt;
&lt;li&gt;El manejo de errores también es complicado, porque los datos devueltos son opcionales.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  ¿Cuáles son las tres opciones de refactorización que ofrece Xcode y en qué se diferencian entre sí?
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;Add Async Wrapper&lt;/code&gt;: Crea un método "wrapper" de tipo &lt;code&gt;async&lt;/code&gt;/&lt;code&gt;await&lt;/code&gt; que invoca el método que usa closures.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;Add Async Alternative&lt;/code&gt;: Escribe una versión alternativa al método que usa closures, pero usando &lt;code&gt;async&lt;/code&gt;/&lt;code&gt;await&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;Convert Function to Async&lt;/code&gt;: Reemplaza la función en cuestión que usa closures, con otra que usa &lt;code&gt;async&lt;/code&gt;/&lt;code&gt;await&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  ¿Por qué el artículo recomienda usar primero un &lt;code&gt;async wrapper&lt;/code&gt; en lugar de reescribir directamente la lógica central?
&lt;/h3&gt;

&lt;p&gt;En el caso de agregar un wrapper, o de agregar una alternativa async, el autor sugiere marcar la versión que usa closure con:&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;@available&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="n"&gt;deprecated&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;renamed&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;"fetchImage(urlRequest:)"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;message&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;"Consider using the async/await alternative."&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Una vez se ponga esa etiqueta, aparecerá un warning en los puntos clientes que se deben modificar.&lt;/p&gt;

&lt;p&gt;Esto permite concentrarse en reescribir la sintaxis &lt;code&gt;async&lt;/code&gt;/&lt;code&gt;await&lt;/code&gt; en el código de producción y en las pruebas, en lugar de preocuparse por la correcta conversión de la lógica asíncrona.&lt;/p&gt;

&lt;p&gt;** LO MAS IMPORTANTE ES RESCRIBIR PRIMERO LAS PRUEBAS PARA QUE USEN EL WRAPPER ASYNC/AWAIT **&lt;/p&gt;

&lt;h3&gt;
  
  
  ¿Qué dos reglas críticas hay que respetar al usar &lt;code&gt;withCheckedThrowingContinuation&lt;/code&gt;?
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Hacer "resume" exactamente una vez:&lt;/strong&gt; 0 veces provoca una fuga. Más de 1, provoca un error en tiempo de ejecución. La variante "checked" (i.e. &lt;code&gt;withCheckedThrowingContinuation&lt;/code&gt;) atrapa doble "resume"s en tiempo de desarrollo.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Evitar deadlocks:&lt;/strong&gt; Si el closure que se pasa al "continuation" está esperando a algo que solo ocurre después del "resume", entonces aparece un "deadlock".&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  ¿Por qué las herramientas de refactorización automática de Xcode no siempre producen el resultado óptimo?
&lt;/h3&gt;

&lt;p&gt;A veces, a pesar de que la firma del método pasa a ser &lt;code&gt;async&lt;/code&gt;/&lt;code&gt;await&lt;/code&gt;, internamente puede usar una aproximación basada en closures, por lo que no termina siendo un refactor muy efectivo.&lt;/p&gt;

&lt;h3&gt;
  
  
  Al leer el código de &lt;code&gt;ImageFetcher&lt;/code&gt;, ¿qué rol cumple el bloque &lt;code&gt;do&lt;/code&gt;-&lt;code&gt;catch&lt;/code&gt; dentro del closure de &lt;code&gt;URLSession&lt;/code&gt;?
&lt;/h3&gt;

&lt;p&gt;Captura un error en el &lt;code&gt;catch&lt;/code&gt; y lo arroja con el "continuation".&lt;/p&gt;

&lt;h3&gt;
  
  
  ¿Cómo cambia la implementación final de &lt;code&gt;ImageFetcherMigrated&lt;/code&gt; respecto a las versiones intermedias generadas por Xcode?
&lt;/h3&gt;

&lt;p&gt;Las versiones intermedias igual hacían la petición con &lt;code&gt;URLSession&lt;/code&gt; usando closures. La versión final de &lt;code&gt;ImageFetcherMigrated&lt;/code&gt; usa &lt;code&gt;URLSession&lt;/code&gt; con su versión &lt;code&gt;async&lt;/code&gt; (i.e. &lt;code&gt;await URLSession.shared.data(for: urlRequest)&lt;/code&gt;).&lt;/p&gt;




&lt;h2&gt;
  
  
  Recordar sin releer
&lt;/h2&gt;

&lt;h3&gt;
  
  
  ¿puedes describir los pasos del proceso de migración recomendado, en orden?
&lt;/h3&gt;

&lt;h3&gt;
  
  
  ¿Qué ventajas concretas tiene la versión final con &lt;code&gt;async&lt;/code&gt;/&lt;code&gt;await&lt;/code&gt; respecto a la versión con closures?
&lt;/h3&gt;




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

&lt;h3&gt;
  
  
  ¿Qué limitaciones actuales tienen las herramientas de Xcode para esta tarea, y qué mejora se menciona para el futuro?
&lt;/h3&gt;

&lt;h3&gt;
  
  
  ¿Cómo se relaciona este proceso de migración con la estrategia general de mantener la estabilidad del código existente?
&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] Herramienta de migración para "Upcoming features"</title>
      <dc:creator>GoyesDev</dc:creator>
      <pubDate>Mon, 25 May 2026 20:26:34 +0000</pubDate>
      <link>https://dev.to/david_goyes_a488f58a17a53/sc-herramienta-de-migracion-para-upcoming-features-2h2g</link>
      <guid>https://dev.to/david_goyes_a488f58a17a53/sc-herramienta-de-migracion-para-upcoming-features-2h2g</guid>
      <description>&lt;h2&gt;
  
  
  Comprensión durante la lectura
&lt;/h2&gt;

&lt;h3&gt;
  
  
  ¿Por qué es importante migrar un proyecto a las upcoming features de Swift 6?
&lt;/h3&gt;

&lt;p&gt;Actualmente son opcionales, pero en un futuro será obligatorio tenerlas.&lt;/p&gt;

&lt;h3&gt;
  
  
  ¿Qué limitaciones tiene la herramienta de migración automática mencionada en el artículo?
&lt;/h3&gt;

&lt;p&gt;En un proyecto de iOS, la herramienta solo pone una advertencia en los puntos donde hace falta la migración. Esto obliga al desarrollador a revisar advertencia por advertencia y darle la solución que corresponda.&lt;/p&gt;

&lt;p&gt;La herramienta de migración automática aplicada a paquetes de SPM funciona de forma independiente.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;swift package migrate &lt;span class="o"&gt;[&lt;/span&gt;&amp;lt;options&amp;gt;] &lt;span class="nt"&gt;--to-feature&lt;/span&gt; &amp;lt;to-feature&amp;gt;
swift package migrate &lt;span class="nt"&gt;--target&lt;/span&gt; &amp;lt;target_name&amp;gt; &lt;span class="nt"&gt;--to-feature&lt;/span&gt; &amp;lt;to-feature&amp;gt;

swift package migrate &lt;span class="nt"&gt;--to-feature&lt;/span&gt; ExistentialAny
swift package migrate &lt;span class="nt"&gt;--target&lt;/span&gt; &lt;span class="s2"&gt;"Diagnostics"&lt;/span&gt; &lt;span class="nt"&gt;--to-feature&lt;/span&gt; ExistentialAny
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  ¿qué hace exactamente el valor Migrate en los Build Settings de Xcode?
&lt;/h3&gt;

&lt;p&gt;Pone una advertencia sobre el punto que debe ser migrado.&lt;/p&gt;

&lt;h3&gt;
  
  
  ¿En qué condición se actualiza el archivo Package.swift al ejecutar el comando de migración?
&lt;/h3&gt;

&lt;p&gt;Si la migración es exitosa, sin errores, se actualiza el archivo Package.swift con:&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="nv"&gt;swiftSettings&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="nf"&gt;enableUpcomingFeature&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"ExistencialAny"&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 releer
&lt;/h2&gt;

&lt;h3&gt;
  
  
  ¿cuál es el comando exacto para migrar únicamente un target específico de un paquete Swift?
&lt;/h3&gt;

&lt;h3&gt;
  
  
  ¿Cuántos fix-its aplicó automáticamente el comando en el ejemplo del artículo y en cuántos archivos?
&lt;/h3&gt;

&lt;h3&gt;
  
  
  ¿Qué propuesta de Swift (SE-XXX) introdujo la característica &lt;code&gt;ExistentialAny&lt;/code&gt; usada como ejemplo?
&lt;/h3&gt;




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

&lt;h3&gt;
  
  
  ¿Qué requisito deben cumplir las propuestas futuras de Swift para incluir soporte de migración, según el artículo?
&lt;/h3&gt;

&lt;h3&gt;
  
  
  En tu opinión, ¿qué ventaja práctica ofrece la migración por terminal frente a la de Xcode para proyectos de gran escala?
&lt;/h3&gt;

&lt;h3&gt;
  
  
  ¿Qué tema aborda la lección siguiente mencionada al final del artículo, y cómo se relaciona con la migración a concurrencia?
&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] El BuildSetting "Approachable Concurrency"</title>
      <dc:creator>GoyesDev</dc:creator>
      <pubDate>Sat, 23 May 2026 16:34:27 +0000</pubDate>
      <link>https://dev.to/david_goyes_a488f58a17a53/sc-el-buildsetting-approachable-concurrency-5e7m</link>
      <guid>https://dev.to/david_goyes_a488f58a17a53/sc-el-buildsetting-approachable-concurrency-5e7m</guid>
      <description>&lt;p&gt;"Approachable concurrency" es la unión de las siguientes propuestas:&lt;/p&gt;

&lt;p&gt;5.9 SE-401: Disable Outward Actor Isolation Inference&lt;br&gt;
6.0 SE-418: Infer Sendable for methods &amp;amp; key path literals&lt;br&gt;
6.0 SE-434: Usability of global-actor-isolated types&lt;br&gt;
6.2 SE-461: nonisolated(nonsending) by Default&lt;br&gt;
6.2 SE-466: Control default actor isolatioin inference&lt;br&gt;
6.2 SE-470: Global-actor isolated conformances&lt;br&gt;
6.2 SE-486: Migration tooling for Swift features&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Enables upcoming features that aim to provide a more approachable path to Swift Concurrency: DisableOutwardActorInference, GlobalActorIsolatedTypesUsability, InferIsolatedConformances, InferSendableFromCaptures, and NonisolatedNonsendingByDefault.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;En el proyecto de iOS se busca &lt;code&gt;SWIFT_APPROACHABLE_CONCURRENCY&lt;/code&gt;.&lt;/p&gt;
&lt;h2&gt;
  
  
  Revisión de las propuestas:
&lt;/h2&gt;
&lt;h3&gt;
  
  
  Disable Outward Actor Isolation Inference
&lt;/h3&gt;

&lt;p&gt;Declarations that are not explicitly annotated with either a global actor or nonisolated can infer global actor isolation from several different places:&lt;/p&gt;

&lt;p&gt;A struct or class containing a wrapped instance property with a global actor-qualified wrappedValue infers actor isolation from that property wrapper:&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;@propertyWrapper&lt;/span&gt;
&lt;span class="kd"&gt;struct&lt;/span&gt; &lt;span class="kt"&gt;UIUpdating&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;Wrapped&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&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;var&lt;/span&gt; &lt;span class="nv"&gt;wrappedValue&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;Wrapped&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;CounterView&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="c1"&gt;// infers @MainActor from use of @UIUpdating&lt;/span&gt;
  &lt;span class="kd"&gt;@UIUpdating&lt;/span&gt; &lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="nv"&gt;intValue&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;Int&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;El código anterior era confuso. Por esta razón:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;This proposal advocates for removing this inference rule when compiling in the Swift 6 language mode. Given the example above, &lt;code&gt;CounterView&lt;/code&gt; would no longer infer &lt;code&gt;@MainActor&lt;/code&gt; isolation in Swift 6.&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  Usability of global-actor-isolated types
&lt;/h3&gt;

&lt;p&gt;Esta propuesta de Swift 6.0 resuelve tres problemas de usabilidad relacionados con tipos que están aislados a actores globales (como &lt;code&gt;@MainActor&lt;/code&gt;).&lt;/p&gt;

&lt;h4&gt;
  
  
  Problema 1: Propiedades &lt;code&gt;var&lt;/code&gt; en &lt;code&gt;structs&lt;/code&gt; aislados
&lt;/h4&gt;

&lt;p&gt;&lt;strong&gt;Antes:&lt;/strong&gt; Si tenías un &lt;code&gt;struct&lt;/code&gt; con &lt;code&gt;@MainActor&lt;/code&gt;, las propiedades &lt;code&gt;var&lt;/code&gt; no podían usarse fuera del actor sin marcarlas &lt;code&gt;nonisolated(unsafe)&lt;/code&gt;, lo cual era innecesariamente alarmante:&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;struct&lt;/span&gt; &lt;span class="kt"&gt;S&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nf"&gt;nonisolated&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;unsafe&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="nv"&gt;x&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;Int&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="c1"&gt;// feo e innecesario&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Después:&lt;/strong&gt; Si la propiedad es de tipo &lt;code&gt;Sendable&lt;/code&gt; (como &lt;code&gt;Int&lt;/code&gt;), Swift infiere automáticamente &lt;code&gt;nonisolated&lt;/code&gt; dentro del mismo módulo, porque acceder a un valor &lt;code&gt;Sendable&lt;/code&gt; nunca puede causar una carrera de datos:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight swift"&gt;&lt;code&gt;&lt;span class="kd"&gt;@MainActor&lt;/span&gt; &lt;span class="kd"&gt;struct&lt;/span&gt; &lt;span class="kt"&gt;S&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="nv"&gt;x&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;Int&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="c1"&gt;// Swift lo trata como nonisolated dentro del módulo&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;La clave es que esto solo aplica dentro del módulo, porque desde afuera alguien podría convertir esa propiedad en "computed" (con lógica aislada al actor) y eso rompería compatibilidad.&lt;/p&gt;

&lt;h4&gt;
  
  
  Problema 2: Closures aislados y @Sendable
&lt;/h4&gt;

&lt;p&gt;&lt;strong&gt;Antes:&lt;/strong&gt; Un closure &lt;code&gt;@MainActor&lt;/code&gt; no era automáticamente &lt;code&gt;@Sendable&lt;/code&gt;, lo que causaba errores absurdos al pasarlo a un &lt;code&gt;Task&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight swift"&gt;&lt;code&gt;&lt;span class="kd"&gt;func&lt;/span&gt; &lt;span class="nf"&gt;test&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;fn&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kd"&gt;@escaping&lt;/span&gt; &lt;span class="kd"&gt;@MainActor&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="kt"&gt;Void&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;fn&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="c1"&gt;// ❌ error: tipo no-Sendable capturado&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;&lt;strong&gt;Después:&lt;/strong&gt; &lt;code&gt;@Sendable&lt;/code&gt; se infiere automáticamente en closures aislados a un actor global. Tiene sentido porque ese closure siempre corre en el mismo actor, así que nunca habrá acceso concurrente. Incluso puede capturar valores non-Sendable de forma segura:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight swift"&gt;&lt;code&gt;&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="kt"&gt;NonSendable&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;test&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;ns&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kt"&gt;NonSendable&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;closure&lt;/span&gt; &lt;span class="o"&gt;=&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="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ns&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c1"&gt;// ✅ seguro, siempre corre en MainActor&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;closure&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;h4&gt;
  
  
  Problema 3: Subclases aisladas de superclases no-Sendable
&lt;/h4&gt;

&lt;p&gt;&lt;strong&gt;Antes:&lt;/strong&gt; Esto daba un error aunque en muchos casos sería perfectamente válido:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight swift"&gt;&lt;code&gt;&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="kt"&gt;Base&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;          &lt;span class="c1"&gt;// no-Sendable&lt;/span&gt;

&lt;span class="kd"&gt;@MainActor&lt;/span&gt;
&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="kt"&gt;Sub&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;Base&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;     &lt;span class="c1"&gt;// ❌ error en Swift 5.10&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;El problema real era que &lt;code&gt;@MainActor&lt;/code&gt; implica &lt;code&gt;Sendable&lt;/code&gt;, lo que permitía pasar &lt;code&gt;Sub&lt;/code&gt; entre contextos de concurrencia heredando estado mutable no protegido de &lt;code&gt;Base&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Después:&lt;/strong&gt; Se permite la subclase aislada, pero sin conformancia a &lt;code&gt;Sendable&lt;/code&gt;. Así se evita el peligro sin bloquear el patrón por completo:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight swift"&gt;&lt;code&gt;&lt;span class="kd"&gt;@MainActor&lt;/span&gt;
&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="kt"&gt;Sub&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;Base&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;  &lt;span class="c1"&gt;// ✅ permitido, pero Sub no es Sendable&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Global-actor isolated conformances
&lt;/h3&gt;

&lt;p&gt;Tipos de datos aislados en &lt;code&gt;MainActor&lt;/code&gt; pueden conformar protocolos en &lt;code&gt;@MainActor&lt;/code&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Inferring &lt;code&gt;Sendable&lt;/code&gt; for methods and key path literals
&lt;/h3&gt;

&lt;h4&gt;
  
  
  Problema 1: Referencias a métodos y &lt;code&gt;@Sendable&lt;/code&gt;
&lt;/h4&gt;

&lt;p&gt;En Swift puedes tomar una referencia a un método sin llamarlo. Esto se llama referencia parcial o unapplied method reference:&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;Counter&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;Sendable&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="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="o"&gt;...&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// Referencia al método sin llamarlo&lt;/span&gt;
&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;fn&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kt"&gt;Counter&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;increment&lt;/span&gt;  &lt;span class="c1"&gt;// tipo: (Counter) -&amp;gt; () -&amp;gt; Void&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;El problema era que al pasar esa referencia a un contexto concurrente, Swift se quejaba de que no era &lt;code&gt;@Sendable&lt;/code&gt;, aunque el tipo &lt;code&gt;Counter&lt;/code&gt; sí lo fuera:&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: error aunque Counter es Sendable&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;let&lt;/span&gt; &lt;span class="nv"&gt;fn&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kt"&gt;Counter&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;increment&lt;/span&gt;  &lt;span class="c1"&gt;// 'Counter.increment' no es @Sendable&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Esto era inconsistente: si &lt;code&gt;Counter&lt;/code&gt; es &lt;code&gt;Sendable&lt;/code&gt;, cualquier referencia a sus métodos también debería serlo, porque no capturan estado no-&lt;code&gt;Sendable&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Después:&lt;/strong&gt; el compilador infiere @Sendable automáticamente:&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;// ✅ Ahora: funciona sin anotaciones&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;let&lt;/span&gt; &lt;span class="nv"&gt;fn&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kt"&gt;Counter&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;increment&lt;/span&gt;  &lt;span class="c1"&gt;// @Sendable inferido&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  Problema 2: Key paths y Sendable
&lt;/h4&gt;

&lt;p&gt;Un key path es una referencia a una propiedad que puedes almacenar y usar después:&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;Person&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="nv"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;String&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;kp&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;\&lt;/span&gt;&lt;span class="kt"&gt;Person&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;  &lt;span class="c1"&gt;// KeyPath&amp;lt;Person, String&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;El problema era que Swift marcaba los key paths como &lt;code&gt;Sendable&lt;/code&gt; de forma conservadora, lo que causaba advertencias confusas incluso cuando no había ningún riesgo real:&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: advertencia innecesaria en contextos no concurrentes&lt;/span&gt;
&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;kp&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;\&lt;/span&gt;&lt;span class="kt"&gt;Person&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;  &lt;span class="c1"&gt;// ⚠️ advertencia: key path debería ser Sendable&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Y al revés, si necesitabas que fuera Sendable explícitamente, no había forma de anotarlo.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Después:&lt;/strong&gt; dos mejoras:&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;// ✅ Sin advertencia si no se usa en contexto concurrente&lt;/span&gt;
&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;kp&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;\&lt;/span&gt;&lt;span class="kt"&gt;Person&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;  &lt;span class="c1"&gt;// Sendable solo se infiere si hace falta&lt;/span&gt;

&lt;span class="c1"&gt;// ✅ Puedes forzarlo explícitamente cuando lo necesitas&lt;/span&gt;
&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;kp&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;KeyPath&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;Person&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;String&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt; &lt;span class="kt"&gt;Sendable&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;\&lt;/span&gt;&lt;span class="kt"&gt;Person&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  nonisolated(nonsending) by Default
&lt;/h4&gt;

&lt;p&gt;Las funciones async no aisladas (nonisolated) siempre saltaban a un executor genérico al ejecutarse. Con esta propuesta, en cambio, heredan el actor del contexto que las llama, a menos que se marquen explícitamente con @concurrent.&lt;/p&gt;

&lt;h2&gt;
  
  
  Para activar manualmente los Upcoming features en un paquete de SPM
&lt;/h2&gt;

&lt;p&gt;Usar &lt;code&gt;.swiftLanguageMode(.v5)&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="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;target&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="nv"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;"YourPackageTarget"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nv"&gt;swiftSettings&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="nf"&gt;swiftLanguageMode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;v5&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;enableUpcomingFeature&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"DisableOutwardActorInference"&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;enableUpcomingFeature&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"GlobalActorIsolatedTypesUsability"&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;enableUpcomingFeature&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"InferIsolatedConformances"&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;enableUpcomingFeature&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"InferSendableFromCaptures"&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;enableUpcomingFeature&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"NonisolatedNonsendingByDefault"&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;
  
  
  Notas del video
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Pasos para implementar concurrency:
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;Escribir código secuencial, de un solo hilo.&lt;/li&gt;
&lt;li&gt;Suspender la ejecución, sin paralelismo.&lt;/li&gt;
&lt;li&gt;Introducir paralelismo para mejorar el desempeño.&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  ¿Cuáles son los nuevos cambios?
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;NonisolatedNonsendingByDefault&lt;/code&gt;.

&lt;ul&gt;
&lt;li&gt;`nonisolated(nonsending) no envía el objeto/estado a otro dominio de aislamiento.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;p&gt;Si se activa &lt;code&gt;Migrate&lt;/code&gt; sobre &lt;code&gt;NonisolatedNonsendingByDefault&lt;/code&gt; entonces aparece un warning sobre el código:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;&lt;/code&gt;&lt;code&gt;swift&lt;br&gt;
// ⚠️ Feature 'NonisolatedNonsendingByDefault' will cause nonisolated async instance method 'performAsync' to run on the calle's actor; use '@concurrency' to preserve behavior.&lt;br&gt;
&lt;/code&gt;&lt;code&gt;&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;En el warning aparece un signo de interrogación para aprender más y también un botón "Fix" para aplicar el cambio.&lt;/p&gt;

&lt;p&gt;Es importante apoyarse en el "Migration tooling" porque la migración manual puede ser peligrosa.&lt;/p&gt;

&lt;h3&gt;
  
  
  Control default actor isolation inference
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Originalmente todo es &lt;code&gt;nonisolated&lt;/code&gt;. Sin embargo, se puede poner &lt;code&gt;MainActor&lt;/code&gt; por defecto en todo.&lt;/li&gt;
&lt;li&gt;Puede ser peligroso usar &lt;code&gt;MainActor&lt;/code&gt; por defecto.&lt;/li&gt;
&lt;li&gt;Para nuevos proyectos, sirve tener &lt;code&gt;MainActor&lt;/code&gt; por defecto. Cuando se requiera mejor desempeño, se puede cambiar a &lt;code&gt;nonisolated&lt;/code&gt; o &lt;code&gt;@concurrent&lt;/code&gt;. Sin embargo, en código legado, es mejor hacer la migración manual.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Global-actor isolated conformances
&lt;/h3&gt;

&lt;p&gt;&lt;code&gt;&lt;/code&gt;&lt;code&gt;swift&lt;br&gt;
@MainActor &lt;br&gt;
final class PersonViewModel {&lt;br&gt;
  let id: UUID&lt;br&gt;
  var name: String&lt;br&gt;
  init(id: UUID, name: String) {&lt;br&gt;
    self.id = id&lt;br&gt;
    self.name = name&lt;br&gt;
  }&lt;br&gt;
}&lt;br&gt;
// ❌ Conformance of 'PersonViewModel' to protocol 'Equatable' crosses into main actor-isolated code and can cause data races&lt;br&gt;
extension PersonViewModel: Equatable {&lt;br&gt;
  static func == (lhs: PersonViewModel, rhs: PersonViewModel) -&amp;gt; Bool {&lt;br&gt;
    lhs.id == rhs.id&lt;br&gt;
  }&lt;br&gt;
}&lt;br&gt;
&lt;/code&gt;&lt;code&gt;&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Soluciones:&lt;/p&gt;

&lt;h4&gt;
  
  
  1. Marcar con &lt;code&gt;nonisolated&lt;/code&gt; el método de &lt;code&gt;Equatable&lt;/code&gt; (i.e. &lt;code&gt;nonisolated static func ==&lt;/code&gt;).
&lt;/h4&gt;

&lt;p&gt;Esto permite usar el método desde cualquier dominio de aislamiento. Sin embargo, al hacer esto, es obligatorio asegurarse que los datos a usar son &lt;code&gt;Sendable&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;&lt;/code&gt;&lt;code&gt;swift&lt;br&gt;
extension PersonViewModel: Equatable {&lt;br&gt;
  nonisolated static func == (lhs: PersonViewModel, rhs: PersonViewModel) -&amp;gt; Bool {&lt;br&gt;
    lhs.id == rhs.id &amp;amp;&amp;amp; lhs.name == rhs.name&lt;br&gt;
    // ❌ Main actor-isolated property 'name' can not be referenced from a nonisolated autoclosure&lt;br&gt;
  }&lt;br&gt;
}&lt;br&gt;
&lt;/code&gt;&lt;code&gt;&lt;/code&gt;&lt;/p&gt;

&lt;h4&gt;
  
  
  2. Conformar un protocolo solo en un actor global (i.e. &lt;code&gt;extension PersonViewModel: @MainActor Equatable&lt;/code&gt;).
&lt;/h4&gt;

&lt;p&gt;Con esto se puede comparar sin problema (usando &lt;code&gt;Equatable&lt;/code&gt;) siempre que se esté en &lt;code&gt;MainActor&lt;/code&gt;. Si se está en otro dominio de aislamiento, habrá un error.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;&lt;/code&gt;&lt;code&gt;swift&lt;br&gt;
extension PersonViewModel: @MainActor Equatable {&lt;br&gt;
  static func == (lhs: PersonViewModel, rhs: PersonViewModel) -&amp;gt; Bool {&lt;br&gt;
    lhs.id == rhs.id &amp;amp;&amp;amp; lhs.name == rhs.name&lt;br&gt;
  }&lt;br&gt;
}&lt;br&gt;
&lt;/code&gt;&lt;code&gt;&lt;/code&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Estrategias de migración
&lt;/h3&gt;

&lt;p&gt;No activar "Approachable Concurrency" de forma grupal. En su lugar, activar las funcionalidades una por una. Luego, hacer un PR por cada "upcoming feature". Esto hará más entendible los cambios.&lt;/p&gt;

&lt;p&gt;Al final de todo el proceso sí se activa "Approachable Concurrency".&lt;/p&gt;

&lt;h3&gt;
  
  
  Algunos consejos:
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;Hacerlo de forma iterativa.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;Sendable&lt;/code&gt; por defecto.&lt;/li&gt;
&lt;li&gt;Evitar refactorizar todo durante la marcha. El foco es concurrency.&lt;/li&gt;
&lt;li&gt;Hacer cambios pequeños en un PR que pueda ser revisado rápidaemtne.&lt;/li&gt;
&lt;li&gt;En nuevos proyectos: activar 1) Swift 6.2, 2) aislamiento por defecto en &lt;code&gt;MainActor&lt;/code&gt; y 3) "Approachable concurrency".&lt;/li&gt;
&lt;li&gt;No aislar todo en &lt;code&gt;MainActor&lt;/code&gt;.&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  ¿Cómo migrar código existente?
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;Encontrar código aislado. Posiblemente un solo archivo o clase pequeña.&lt;/li&gt;
&lt;li&gt;Incrementar la validación estricta de concurrencia. Pasar primero a &lt;code&gt;Targeted&lt;/code&gt; y luego &lt;code&gt;Complete&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Habilitar "Upcoming Features" uno a uno.&lt;/li&gt;
&lt;li&gt;Deshabilitar/reiniciar los settings modificados.&lt;/li&gt;
&lt;li&gt;Someter PR a revisión.&lt;/li&gt;
&lt;li&gt;Cuando todo esté listo, activar Swift 6.2.&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  Error en tiempo de ejecución
&lt;/h3&gt;

&lt;p&gt;"Block was expected to execute on queue []"&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;El &lt;code&gt;sink&lt;/code&gt; de combine no funciona bien con atributos marcados con &lt;code&gt;MainActor&lt;/code&gt;. Nada impide llamar &lt;code&gt;sink&lt;/code&gt; desde un hilo de segundo plano. &lt;a href="https://www.avanderlee.com/concurrency/combine-and-swift-concurrency-a-threading-risk/" rel="noopener noreferrer"&gt;Artículo&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  &lt;code&gt;for await&lt;/code&gt; no puede tener &lt;code&gt;return&lt;/code&gt; en su interior.
&lt;/h3&gt;

&lt;p&gt;En lugar de usar &lt;code&gt;return&lt;/code&gt;, debe haber &lt;code&gt;continue&lt;/code&gt; al interior de &lt;code&gt;for await&lt;/code&gt;.&lt;/p&gt;




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

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

</description>
      <category>swift</category>
      <category>ios</category>
      <category>concurrency</category>
      <category>swiftconcurrency</category>
    </item>
    <item>
      <title>[SC] Pasos para migrar a Swift 6 y verificación estricta de concurrencia</title>
      <dc:creator>GoyesDev</dc:creator>
      <pubDate>Fri, 22 May 2026 11:34:25 +0000</pubDate>
      <link>https://dev.to/david_goyes_a488f58a17a53/sc-pasos-para-migrar-a-swift-6-y-verificacion-estricta-de-concurrencia-27d0</link>
      <guid>https://dev.to/david_goyes_a488f58a17a53/sc-pasos-para-migrar-a-swift-6-y-verificacion-estricta-de-concurrencia-27d0</guid>
      <description>&lt;h2&gt;
  
  
  Comprensión durante la lectura
&lt;/h2&gt;

&lt;h3&gt;
  
  
  ¿Por qué se recomienda comenzar la migración con un fragmento de código aislado?
&lt;/h3&gt;

&lt;p&gt;Entre menos dependencias tenga un fragmento de código más fácil es hacer la migración. Que haya dependencias significa que aparecerán casos donde, luego de arreglar 50 errores, aparecen 80 más.&lt;/p&gt;

&lt;h3&gt;
  
  
  ¿Qué ventaja ofrece actualizar las dependencias de terceros antes de habilitar el "strict concurrency checking"?
&lt;/h3&gt;

&lt;p&gt;Puede ser que el código que planeo migrar dependa de otras bibliotecas de terceros. En este caso, vale la pena primero actualizar dichas dependencias, en caso de que estas estén al día con el uso de Swift Concurrency. &lt;/p&gt;

&lt;p&gt;De hecho, si las dependencias de terceros ya introdujeron cambios para estar al día con &lt;code&gt;strict concurrency checking&lt;/code&gt;, muy probablemente se le exigirá a mi código que introduzca algunos cambios incluso antes de habilitar el "strict concurrency checking".&lt;/p&gt;

&lt;h3&gt;
  
  
  ¿Vale la pena usar &lt;code&gt;@MainActor&lt;/code&gt; por defecto?
&lt;/h3&gt;

&lt;p&gt;Si se está trabajando en una aplicación móvil, es buena idea activar &lt;code&gt;@MainActor&lt;/code&gt; por defecto. Esto va a resolver muchas advertencias y errores.&lt;/p&gt;

&lt;p&gt;En un proyecto de iOS buscar "Default Actor Isolation". En un paquete de SPM:&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="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;target&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="nv"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;"DefaultActorIsolationPackage"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nv"&gt;swiftSettings&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="nf"&gt;defaultIsolation&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;MainActor&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="k"&gt;self&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é diferencia hay entre los niveles &lt;code&gt;Minimal&lt;/code&gt;, &lt;code&gt;Targeted&lt;/code&gt; y &lt;code&gt;Complete&lt;/code&gt; de &lt;code&gt;strict concurrency checking&lt;/code&gt;?
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Minimal&lt;/strong&gt; Solo revisa código que tenga palabras clave de concurrencia explícita: &lt;code&gt;async&lt;/code&gt;/&lt;code&gt;await&lt;/code&gt;, &lt;code&gt;@Sendable&lt;/code&gt;, &lt;code&gt;@MainActor&lt;/code&gt;. Todo lo demás se ignora.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Targeted&lt;/strong&gt; revisa todo tipo que conforma &lt;code&gt;Sendable&lt;/code&gt;, aunque no se &lt;code&gt;async&lt;/code&gt; directamente.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Complete&lt;/strong&gt; revisa absolutamente todo el código base, incluso si no toca concurrencia. Este nivel pregunta: "¿Podría este código, algún día, cruzar un isolation domain".&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Consideremos los siguientes escenarios:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight swift"&gt;&lt;code&gt;&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="kt"&gt;UserCache&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="nv"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;String&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;""&lt;/span&gt;
  &lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="nv"&gt;age&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;Int&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="kd"&gt;func&lt;/span&gt; &lt;span class="nf"&gt;loadUser&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;cache&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kt"&gt;UserCache&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
  &lt;span class="n"&gt;cache&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"Ana"&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Minimal&lt;/strong&gt;: No hay warning porque no hay &lt;code&gt;async&lt;/code&gt;, &lt;code&gt;@Sendable&lt;/code&gt; ni &lt;code&gt;@MainActor&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Targeted&lt;/strong&gt;: No hay warning porque no conforma &lt;code&gt;Sendable&lt;/code&gt; ni usa concurrencia.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Complete&lt;/strong&gt;: warning - &lt;code&gt;UserCache&lt;/code&gt; se un &lt;code&gt;class&lt;/code&gt; con propiedades mutables y no es &lt;code&gt;Sendable&lt;/code&gt;.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight swift"&gt;&lt;code&gt;&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="kt"&gt;UserCache&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="nv"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;String&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&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;doWork&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;completion&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kd"&gt;@escaping&lt;/span&gt; &lt;span class="kd"&gt;@Sendable&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;UserCache&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="kt"&gt;Void&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;cache&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kt"&gt;UserCache&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
  &lt;span class="nf"&gt;completion&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;cache&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c1"&gt;// captura UserCache dentro de @Sendable&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Minimal&lt;/strong&gt;: warning - El parámetro es &lt;code&gt;@Sendable&lt;/code&gt;, pero &lt;code&gt;UserCache&lt;/code&gt; no conforma &lt;code&gt;Sendable&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Targeted&lt;/strong&gt;: warning - Igual que minimal.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Complete&lt;/strong&gt;: error - Convierte en error el warning de &lt;code&gt;Sendable&lt;/code&gt;.
&lt;/li&gt;
&lt;/ul&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;Config&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;Sendable&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="nv"&gt;timeout&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;Int&lt;/span&gt;
  &lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="nv"&gt;logger&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;Logger&lt;/span&gt; &lt;span class="c1"&gt;// Logger es una class, no Sendable&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="kt"&gt;Logger&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;prefix&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;String&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&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;run&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;config&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;Config&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;// código síncrono, sin async&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Minimal&lt;/strong&gt;: nada - &lt;code&gt;run&lt;/code&gt; es síncrono, así que no valida nada.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Targeted&lt;/strong&gt;: error - &lt;code&gt;Config&lt;/code&gt; es &lt;code&gt;Sendable&lt;/code&gt;, pero su propiedad &lt;code&gt;logger&lt;/code&gt; no.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Complete&lt;/strong&gt;: error - Igual que Targeted. Además, advierte que &lt;code&gt;Logger&lt;/code&gt; no es &lt;code&gt;Sendable&lt;/code&gt; y se puede usar en cualquier otro lado.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;En SPM se activa así:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight swift"&gt;&lt;code&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;target&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="nv"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;"CoreExtensions"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nv"&gt;dependencies&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;"Logging"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
  &lt;span class="nv"&gt;path&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;"CoreExtensions/Sources"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nv"&gt;swiftSettings&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="c1"&gt;/// Used to be like this in Xcode 14:&lt;/span&gt;
    &lt;span class="kt"&gt;SwiftSetting&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;unsafeFlags&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="s"&gt;"-Xfrontend"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"-strict-concurrency=complete"&lt;/span&gt;&lt;span class="p"&gt;]),&lt;/span&gt;
    &lt;span class="c1"&gt;/// Xcode 15, 16, 26, and up. Remove `=targeted` to use the default `complete`. Potentially isolate to a platform to further reduce scope.&lt;/span&gt;
    &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;enableExperimentalFeature&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"StrictConcurrency=targeted"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;when&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;platforms&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;macOS&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;
  
  
  ¿En qué situación tendría sentido quedarse en un paso intermedio como agregar alternativas &lt;code&gt;async&lt;/code&gt; en lugar de migrar por completo?
&lt;/h3&gt;

&lt;p&gt;Puede ser que el fragmento de código aislado sobre el que estemos trabajando sea una dependencia de algún otro módulo. En este caso, se puede proveer una alternativa &lt;code&gt;async&lt;/code&gt;/&lt;code&gt;await&lt;/code&gt; del API que permita a otro desarrollador migrar los clientes a Swift Concurrency.&lt;/p&gt;

&lt;p&gt;Al proveer una alternativa &lt;code&gt;async&lt;/code&gt;/&lt;code&gt;await&lt;/code&gt; se puede agregar un "Async wrapper" desde el menú "Refactor" y poner la siguiente etiqueta en el código que recibe closures:&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;@available&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="n"&gt;deprecated&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;renamed&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;"fetchImage(urlRequest:)"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;message&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;"Consider using the async/await alternative."&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;La etiqueta anterior va a levantar una advertencia en todos los puntos donde se use la versión con closures, lo que permitirá identificar con rapidez donde se debe reemplazar con la versión que usa &lt;code&gt;async&lt;/code&gt;/&lt;code&gt;await&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Usar un "Async wrapper" puede ser útil porque permite a los otros desarrolladores avanzar en la migración mientras yo me enfoco en construir la solución final de Swift Concurrency por detrás.&lt;/p&gt;

&lt;h3&gt;
  
  
  ¿Por qué es útil conformar &lt;code&gt;Sendable&lt;/code&gt; en los tipos de datos de un paquete?
&lt;/h3&gt;

&lt;p&gt;Un paquete puede ser ampliamente usado por algún cliente. En este caso, conviene conformar &lt;code&gt;Sendable&lt;/code&gt; para que se pueda usar con tranquilidad en lugares donde sí hay cambios de dominio de aislamiento.&lt;/p&gt;

&lt;h3&gt;
  
  
  ¿Qué relación existe entre el &lt;code&gt;swift-tools-version&lt;/code&gt; y el modo de lenguaje Swift 6?
&lt;/h3&gt;

&lt;p&gt;&lt;code&gt;swift-tools-version&lt;/code&gt; permite elegir la versión del lenguaje de un paquete (de SPM). Al elegir &lt;code&gt;// swift-tools-version: 6.0&lt;/code&gt; luego se puede poner en versión 5 a algunas dependencias específicas con &lt;code&gt;.swiftLanguageMode(.v5)&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="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;target&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="nv"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;"CoreNetworking"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nv"&gt;swiftSettings&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="nf"&gt;swiftLanguageMode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;v5&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 releer
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Sin mirar el artículo, ¿puedes enumerar los 9 pasos de la migración en orden?
&lt;/h3&gt;

&lt;h3&gt;
  
  
  ¿Cómo explicarías con tus propias palabras la diferencia entre &lt;code&gt;.swiftLanguageMode(.v5)&lt;/code&gt; y cambiar el &lt;code&gt;swift-tools-version&lt;/code&gt; a 6.0?
&lt;/h3&gt;

&lt;h3&gt;
  
  
  ¿Qué hace exactamente el atributo &lt;code&gt;@available(*, deprecated, renamed:)&lt;/code&gt; y por qué se prefiere sobre la versión sin &lt;code&gt;deprecated&lt;/code&gt;?
&lt;/h3&gt;




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

&lt;h3&gt;
  
  
  ¿Qué pasos del proceso considera el autor como opcionales y por qué?
&lt;/h3&gt;

&lt;h3&gt;
  
  
  ¿De qué manera el concepto de &lt;code&gt;Default Actor Isolation&lt;/code&gt; en Swift 6.2 cambia la estrategia de migración respecto a versiones anteriores?
&lt;/h3&gt;

&lt;h3&gt;
  
  
  Si tuvieras que migrar un proyecto con muchas dependencias entrelazadas, ¿qué ajustes harías al orden propuesto en el artículo?
&lt;/h3&gt;

&lt;h3&gt;
  
  
  ¿Qué relación existe entre &lt;code&gt;Approachable Concurrency&lt;/code&gt; y los "upcoming features" mencionados al final?
&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] Seis hábitos para una migración exitosa hacia Swift 6</title>
      <dc:creator>GoyesDev</dc:creator>
      <pubDate>Tue, 19 May 2026 11:38:46 +0000</pubDate>
      <link>https://dev.to/david_goyes_a488f58a17a53/sc-l7l</link>
      <guid>https://dev.to/david_goyes_a488f58a17a53/sc-l7l</guid>
      <description>&lt;h2&gt;
  
  
  Comprensión durante la lectura
&lt;/h2&gt;

&lt;h3&gt;
  
  
  ¿Por qué el autor recomienda abordar la migración por iteraciones en lugar de hacerlo todo de una vez?
&lt;/h3&gt;

&lt;p&gt;Es más fácil migrar 30 minutos al día por varios días, que dejar la aplicación rota un largo tiempo mientras se arreglan todos los errores. Para esto, activar el "chequeo" estricto de swift, arreglar algunos "warnings" y luego volver a apagarlo.&lt;/p&gt;

&lt;h3&gt;
  
  
  ¿Qué significa hacer los tipos "&lt;code&gt;Sendable&lt;/code&gt; por defecto" y por qué es relevante para equipos de trabajo?
&lt;/h3&gt;

&lt;p&gt;El nuevo código debe escribirse conformando &lt;code&gt;Sendable&lt;/code&gt; por defecto y usando &lt;code&gt;async&lt;/code&gt;/&lt;code&gt;await&lt;/code&gt;. La idea es no usar el paradigma viejo en el código nuevo.&lt;/p&gt;

&lt;h3&gt;
  
  
  ¿Cuándo y por qué debería usarse el modo Swift 6 en proyectos nuevos, aunque el proyecto principal aún no haya migrado?
&lt;/h3&gt;

&lt;p&gt;Activar Swift 6 temporalmente y revisar que el código nuevo pase la validación. De esa forma se evita aumentar la deuda técnica y que crezca el scope de la migración.&lt;/p&gt;

&lt;h3&gt;
  
  
  ¿Por qué el autor advierte en contra de refactorizar durante la migración, si en principio refactorizar es algo positivo?
&lt;/h3&gt;

&lt;p&gt;El autor sugiere concentrarse en hacer la migración a Swift 6 y no hacer ningún refactor en el camino, a no ser que el refactor sea algo bloqueante para la migración.&lt;/p&gt;

&lt;h3&gt;
  
  
  ¿Qué ventaja tiene abrir pull requests pequeños y enfocados durante el proceso de migración?
&lt;/h3&gt;

&lt;p&gt;Los PRs grandes son más difíciles de revisar y menos probable de ser integrados rápidamente. Por esto, si se actualizó una sola clase a Swift Concurrency, es buena idea abrir un PR e integrarlo en la rama &lt;code&gt;feature/swift-6-migration&lt;/code&gt;. Esto es un checkpoint pequeño durante la migración y es una medida de progreso.&lt;/p&gt;

&lt;h3&gt;
  
  
  ¿Cuál es el riesgo de abusar del atributo &lt;code&gt;@MainActor&lt;/code&gt; y en qué casos sí tiene sentido usarlo ampliamente?
&lt;/h3&gt;

&lt;p&gt;La mayor parte de aplicaciones pueden tener &lt;code&gt;@MainActor&lt;/code&gt; por defecto activado. Sin embargo, no siempre es buena idea marcar absolutamente todo con &lt;code&gt;@MainActor&lt;/code&gt;, sino que conviene pensar si se puede aislar el código en otro actor.&lt;/p&gt;




&lt;h2&gt;
  
  
  Recordar sin releer
&lt;/h2&gt;




&lt;h2&gt;
  
  
  Revisión y síntesis
&lt;/h2&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] Swift Concurrency Extras (Point-Free)</title>
      <dc:creator>GoyesDev</dc:creator>
      <pubDate>Thu, 14 May 2026 11:49:44 +0000</pubDate>
      <link>https://dev.to/david_goyes_a488f58a17a53/sc-swift-concurrency-extras-point-free-55fg</link>
      <guid>https://dev.to/david_goyes_a488f58a17a53/sc-swift-concurrency-extras-point-free-55fg</guid>
      <description>&lt;h2&gt;
  
  
  Comprensión durante la lectura
&lt;/h2&gt;

&lt;h3&gt;
  
  
  ¿Por qué las pruebas asíncronas en Swift pueden ser inestables (flaky) cuando se usan tareas no estructuradas?
&lt;/h3&gt;

&lt;p&gt;Aunque el artículo era sobre pruebas inestables en relación con asincronismo, en realidad tenía que ver con la incapacidad de detectar un cambio interno en un método sobre una variable que podía cambiar varias veces y una prueba de caracterización no servía.&lt;/p&gt;

&lt;h3&gt;
  
  
  ¿Qué es &lt;code&gt;withMainSerialExecutor&lt;/code&gt; y cuál es su propósito dentro de los tests?
&lt;/h3&gt;

&lt;p&gt;La biblioteca "Swift Concurrency Extras" ofrece el método &lt;a href="https://swiftpackageindex.com/pointfreeco/swift-concurrency-extras/1.3.2/documentation/concurrencyextras/withmainserialexecutor(operation:)-6s3c0" rel="noopener noreferrer"&gt;&lt;code&gt;withMainSerialExecutor(operation:)&lt;/code&gt;&lt;/a&gt; que ejecuta cierto código en el executor serial del &lt;code&gt;MainActor&lt;/code&gt;. Esto implica que, para que funcione, tiene que aislarse la prueba o la suite de pruebas en &lt;code&gt;MainActor&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Por otro lado, es obligatorio que donde se use &lt;code&gt;withMainSerialExecutor&lt;/code&gt; se defina la suite como serial:&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;@Suite&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;serialized&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;final&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="kt"&gt;ImageFetcherSwiftTesting&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;// ...&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Se usa de la siguiente manera:&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;await&lt;/span&gt; &lt;span class="n"&gt;withMainSerialExecutor&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;// Everything performed in this scope is performed serially...&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 artículo se usa en conjunto con &lt;code&gt;await Task.yield()&lt;/code&gt; para hacer que una &lt;code&gt;Task&lt;/code&gt; ceda la ejecución a otra. Particularmente, se tenía una &lt;code&gt;Task&lt;/code&gt; en la prueba que envolvía el llamado al código de producción que también ejecutaba una &lt;code&gt;Task&lt;/code&gt; (i.e. &lt;code&gt;downloadImage: (URL) async throws -&amp;gt; Data&lt;/code&gt;).&lt;/p&gt;

&lt;h3&gt;
  
  
  ¿Cómo funciona &lt;code&gt;Task.yield()&lt;/code&gt; y por qué su comportamiento varía dependiendo del ejecutor?
&lt;/h3&gt;

&lt;p&gt;&lt;code&gt;Task.yield()&lt;/code&gt; cede el funcionamiento a otra tarea que esté esperando. Si la tarea en cuestión tiene la prioridad más alta, entonces vuelve a tomar el control.&lt;/p&gt;

&lt;p&gt;Si el executor está ocupado con alguna otra prueba, entonces el comportamiento de &lt;code&gt;Task.yield()&lt;/code&gt; no va a conmutar entre dos &lt;code&gt;Task&lt;/code&gt; como se pretende. Por esta razón, se aísla cierto bloque de código con &lt;code&gt;withMainSerialExecutor&lt;/code&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  ¿Cuál es la diferencia entre usar &lt;code&gt;Task.yield()&lt;/code&gt; con y sin el ejecutor serial principal?
&lt;/h3&gt;

&lt;p&gt;Sin el ejecutor serial principal, no se puede garantizar conmutación entre dos tareas.&lt;/p&gt;

&lt;h3&gt;
  
  
  ¿Cómo se integra esta solución con &lt;code&gt;XCTest&lt;/code&gt; y con Swift Testing respectivamente?
&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;@Suite&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;serialized&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;final&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="kt"&gt;ImageFetcherSwiftTesting&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;/// By running the test using a main serial executor, we allow ourselves to use `Task.yield()` and read state in between.&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;isLoadingWithMainSerialExecutor&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;try&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;withMainSerialExecutor&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;imageFetcher&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kt"&gt;ImageFetcher&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;downloadImage&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;url&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt;

        &lt;span class="c1"&gt;/// Yield here to allow the test to continue evaluation. This allows us to check the `isLoading` state.&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;yield&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

        &lt;span class="c1"&gt;/// Return plain `Data()` for this test as we're just interested in the `isLoading` state.&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="kt"&gt;Data&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
      &lt;span class="p"&gt;})&lt;/span&gt;

      &lt;span class="c1"&gt;/// Call into the `fetchImage` method to ensure the `isLoading` state flips to `true` and `false`.&lt;/span&gt;
      &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;task&lt;/span&gt; &lt;span class="o"&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;_&lt;/span&gt; &lt;span class="o"&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="n"&gt;imageFetcher&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;fetchImage&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
          &lt;span class="nv"&gt;imageURL&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;URL&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;string&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;"https://example-image.url"&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="p"&gt;}&lt;/span&gt;

      &lt;span class="c1"&gt;/// Suspends the current test task and allow the above task to start executing up until `downloadImage(...)` is called.&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;yield&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

      &lt;span class="c1"&gt;/// Check the `isLoading` state while we're 'paused' just at `downloadImage`.&lt;/span&gt;
      &lt;span class="cp"&gt;#expect(imageFetcher.isLoading == true)&lt;/span&gt;

      &lt;span class="c1"&gt;/// Await the result of the image fetching.&lt;/span&gt;
      &lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;task&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt;

      &lt;span class="c1"&gt;/// Validate that `isLoading` restores to `false`.&lt;/span&gt;
      &lt;span class="cp"&gt;#expect(imageFetcher.isLoading == false)&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 artículo recomienda usar &lt;code&gt;.serialized&lt;/code&gt; en suites de Swift Testing?
&lt;/h3&gt;

&lt;p&gt;&lt;code&gt;withMainSerialExecutor&lt;/code&gt; sobreescribe el ejecutor global de Swift con el ejecutor serial principal. Por esta razón, cuando se usa, todas las tareas quedarán encoladas en el ejecutor serial principal hasta que el scope del ejecutor termine.&lt;/p&gt;

&lt;p&gt;Si se ejecutan las pruebas en paralelo, esto afectará a las pruebas simultáneamente. Por esto se debe serializar la suite de pruebas.&lt;/p&gt;




&lt;h2&gt;
  
  
  Recordar sin releer
&lt;/h2&gt;

&lt;h3&gt;
  
  
  ¿Podrías explicar con tus propias palabras cómo el ejecutor serial resuelve la inestabilidad de los tests?
&lt;/h3&gt;

&lt;h3&gt;
  
  
  ¿Qué advertencias hace el autor sobre el uso de &lt;code&gt;withMainSerialExecutor&lt;/code&gt;?
&lt;/h3&gt;




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

&lt;h3&gt;
  
  
  ¿En qué escenarios de tu propio proyecto aplicarías esta técnica y en cuáles no sería necesaria?
&lt;/h3&gt;

&lt;h3&gt;
  
  
  ¿Qué limitaciones tiene este enfoque y cómo las mitigarías?
&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] Probando código concurrente con SwiftTesting</title>
      <dc:creator>GoyesDev</dc:creator>
      <pubDate>Wed, 13 May 2026 12:23:25 +0000</pubDate>
      <link>https://dev.to/david_goyes_a488f58a17a53/sc-probando-codigo-concurrente-con-swifttesting-1568</link>
      <guid>https://dev.to/david_goyes_a488f58a17a53/sc-probando-codigo-concurrente-con-swifttesting-1568</guid>
      <description>&lt;h2&gt;
  
  
  Comprensión durante la lectura
&lt;/h2&gt;

&lt;h3&gt;
  
  
  ¿Qué diferencias fundamentales existen entre XCTest y Swift Testing?
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;No se usa el API de &lt;code&gt;XCTest&lt;/code&gt;, o sea clases como &lt;a href="https://developer.apple.com/documentation/xctest/xctestcase" rel="noopener noreferrer"&gt;&lt;code&gt;XCTestCase&lt;/code&gt;&lt;/a&gt; o &lt;a href="https://developer.apple.com/documentation/xctest/xctassert" rel="noopener noreferrer"&gt;&lt;code&gt;XCTAssert&lt;/code&gt;&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;Swift Testing no soporta el uso de &lt;a href="https://developer.apple.com/documentation/xctest/xctestexpectation" rel="noopener noreferrer"&gt;&lt;code&gt;XCTestExpectation&lt;/code&gt;&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;Se prefiere el uso de &lt;code&gt;struct&lt;/code&gt; sobre &lt;code&gt;class&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Se usan macros como &lt;code&gt;@Test&lt;/code&gt;, &lt;code&gt;@Suite&lt;/code&gt;, &lt;code&gt;#expect&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  ¿Por qué las &lt;code&gt;expectations&lt;/code&gt; no funcionan en Swift Testing y cómo se reemplazan?
&lt;/h3&gt;

&lt;p&gt;Swift Testing no soporta el uso de &lt;code&gt;XCTestExpectation&lt;/code&gt; porque es una biblioteca diferente.&lt;/p&gt;

&lt;p&gt;En su lugar se puede combinar el uso de:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;a href="https://developer.apple.com/documentation/swift/withcheckedcontinuation(isolation:function:_:)" rel="noopener noreferrer"&gt;&lt;code&gt;withCheckedContinuation(isolation:function:_:)&lt;/code&gt;&lt;/a&gt; para poder envolver el llamado de un código asíncrono que no tiene &lt;code&gt;async&lt;/code&gt; en la firma&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://developer.apple.com/documentation/observation/withobservationtracking(_:onchange:)" rel="noopener noreferrer"&gt;&lt;code&gt;withObservationTracking(_:onChange:)&lt;/code&gt;&lt;/a&gt; para detectar cambios en alguna propiedad y, ante esto, invocar &lt;a href="https://developer.apple.com/documentation/swift/checkedcontinuation/resume()" rel="noopener noreferrer"&gt;&lt;code&gt;resume()&lt;/code&gt;&lt;/a&gt; sobre el &lt;a href="https://developer.apple.com/documentation/swift/checkedcontinuation" rel="noopener noreferrer"&gt;&lt;code&gt;CheckedContinuation&lt;/code&gt;&lt;/a&gt;.&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  ¿Qué rol juegan &lt;code&gt;withCheckedContinuation&lt;/code&gt; y &lt;code&gt;confirmation()&lt;/code&gt; al probar código asíncrono?
&lt;/h3&gt;

&lt;p&gt;&lt;code&gt;withCheckedContinuation&lt;/code&gt; sirve para poner un &lt;code&gt;await&lt;/code&gt; sobre un código asíncrono que no tenía &lt;code&gt;async&lt;/code&gt; en su firma. Este código asíncrono debe llamar &lt;code&gt;resume()&lt;/code&gt; sobre el &lt;code&gt;CheckedContinuation&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://developer.apple.com/documentation/testing/confirmation(_:expectedcount:isolation:sourcelocation:_:)-l3il" rel="noopener noreferrer"&gt;&lt;code&gt;confirmation(_:expectedCount:isolation:sourceLocation:_:)&lt;/code&gt;&lt;/a&gt; confirma que cierto evento ocurrió durante el llamado de una función. Este método recibe un &lt;code&gt;body&lt;/code&gt; con &lt;code&gt;async&lt;/code&gt; en su firma, cuenta cuántas veces se invocó el &lt;a href="https://developer.apple.com/documentation/testing/confirmation" rel="noopener noreferrer"&gt;&lt;code&gt;Confirmation&lt;/code&gt;&lt;/a&gt; mientras estuvo esperando el &lt;code&gt;body&lt;/code&gt; (i.e. &lt;code&gt;await body(confirmation)&lt;/code&gt;).&lt;/p&gt;

&lt;p&gt;En la práctica este último método sirve para ver si efectivamente hubo la modificación que se esperaba. En el artículo se usó en conjunto con &lt;code&gt;withObservationTracking(_:onChange:)&lt;/code&gt; para detectar si hubo un cambio en &lt;code&gt;articleSearcher.searchResults&lt;/code&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  ¿Cómo se reemplazan &lt;code&gt;setUp&lt;/code&gt; y &lt;code&gt;tearDown&lt;/code&gt; en Swift Testing?
&lt;/h3&gt;

&lt;p&gt;&lt;code&gt;setUp&lt;/code&gt; y &lt;code&gt;tearDown&lt;/code&gt; se reemplazan con &lt;code&gt;init&lt;/code&gt; y &lt;code&gt;deinit&lt;/code&gt; (para este último se requiere usar &lt;code&gt;class&lt;/code&gt; en lugar de &lt;code&gt;struct&lt;/code&gt;).&lt;/p&gt;

&lt;h3&gt;
  
  
  ¿Por qué no se puede llamar código &lt;code&gt;async&lt;/code&gt; dentro de &lt;code&gt;deinit&lt;/code&gt; y cómo se soluciona?
&lt;/h3&gt;

&lt;p&gt;Se supone que &lt;code&gt;deinit&lt;/code&gt; se llama porque ya se va a liberar el objeto de memoria - No se puede retrasar más esta operación, así que no se puede retener &lt;code&gt;self&lt;/code&gt; ni ningún atributo de la prueba.&lt;/p&gt;

&lt;p&gt;Para solucionarlo se requiere llamar el código &lt;code&gt;async&lt;/code&gt; que se quiere que vaya en el &lt;code&gt;deinit&lt;/code&gt;, directamente dentro del método de prueba.&lt;/p&gt;

&lt;p&gt;Una solución alternativa consiste en definir un &lt;a href="https://developer.apple.com/documentation/testing/testscoping" rel="noopener noreferrer"&gt;&lt;code&gt;TestScoping&lt;/code&gt;&lt;/a&gt;, que es un protocolo que le dice al test runner que ejecute un código personalizado antes o después de que ejecuta la suite o función de pruebas. Lo anterior quiere decir que se usa en conjunto con &lt;a href="https://developer.apple.com/documentation/testing/suitetrait" rel="noopener noreferrer"&gt;&lt;code&gt;SuiteTrait&lt;/code&gt;&lt;/a&gt; y/o &lt;a href="https://developer.apple.com/documentation/testing/testtrait" rel="noopener noreferrer"&gt;&lt;code&gt;TestTrait&lt;/code&gt;&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Particularmente, si lo que se requiere es manipular el "sut" entonces se lo puede inyectar en una variable estática marcada con el macro &lt;a href="https://developer.apple.com/documentation/swift/tasklocal" rel="noopener noreferrer"&gt;&lt;code&gt;TaskLocal&lt;/code&gt;&lt;/a&gt; para poder usarla desde el contexto de un &lt;code&gt;Task&lt;/code&gt;.&lt;/p&gt;

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

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight swift"&gt;&lt;code&gt;&lt;span class="kd"&gt;struct&lt;/span&gt; &lt;span class="kt"&gt;Environment&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;@TaskLocal&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;articleSearcher&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kt"&gt;ArticleSearcher&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight swift"&gt;&lt;code&gt;&lt;span class="kd"&gt;struct&lt;/span&gt; &lt;span class="kt"&gt;ArticleSearcherDatabaseTrait&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;SuiteTrait&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;TestTrait&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;TestScoping&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;provideScope&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="nv"&gt;test&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;Test&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nv"&gt;testCase&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;Test&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="kt"&gt;Case&lt;/span&gt;&lt;span class="p"&gt;?,&lt;/span&gt;
    &lt;span class="n"&gt;performing&lt;/span&gt; &lt;span class="nv"&gt;function&lt;/span&gt;&lt;span class="p"&gt;:&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="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="kt"&gt;Void&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;"Running for test &lt;/span&gt;&lt;span class="se"&gt;\(&lt;/span&gt;&lt;span class="n"&gt;test&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;name&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;let&lt;/span&gt; &lt;span class="nv"&gt;articleSearcher&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kt"&gt;ArticleSearcher&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;ArticleSearcherSwiftTesting&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="kt"&gt;Environment&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;$articleSearcher&lt;/span&gt;
      &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;withValue&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;articleSearcher&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;articleSearcher&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;prepareDatabase&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;function&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;articleSearcher&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;closeDatabase&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;@Test&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;ArticleSearcherDatabaseTrait&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;testEmptyQuery&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;await&lt;/span&gt; &lt;span class="kt"&gt;Environment&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;articleSearcher&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;search&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;""&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="cp"&gt;#expect(&lt;/span&gt;
    &lt;span class="kt"&gt;Environment&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;articleSearcher&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;searchResults&lt;/span&gt;
      &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="kt"&gt;ArticleSearcher&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;articleTitlesDatabase&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é hace exactamente el macro &lt;code&gt;@Test&lt;/code&gt; y en qué se diferencia de &lt;code&gt;XCTestCase&lt;/code&gt;?
&lt;/h3&gt;

&lt;p&gt;Marca una función como prueba para ser ejecutada por el runner de pruebas.&lt;/p&gt;

&lt;h3&gt;
  
  
  ¿Cuándo conviene usar &lt;code&gt;withCheckedContinuation&lt;/code&gt; versus &lt;code&gt;confirmation()&lt;/code&gt;?
&lt;/h3&gt;

&lt;p&gt;El primero es para convertir código asíncrono que recibe closures, en &lt;code&gt;async/await&lt;/code&gt;. El segundo es para validar si un evento ocurre durante el llamado de una función &lt;code&gt;async&lt;/code&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  ¿Qué protocolos implementa &lt;code&gt;ArticleSearcherDatabaseTrait&lt;/code&gt; y para qué sirve cada uno?
&lt;/h3&gt;

&lt;p&gt;Implementa &lt;code&gt;SuiteTrait&lt;/code&gt; y &lt;code&gt;TestTrait&lt;/code&gt;. El primero sirve para agregar código antes y después de la ejecución de todos los métodos de la suite de pruebas, y el segundo solo cubre a una sola función de pruebas.&lt;/p&gt;

&lt;h3&gt;
  
  
  ¿Qué hace &lt;code&gt;@TaskLocal&lt;/code&gt; y por qué es importante en el contexto de los "Test Scoping Traits"?
&lt;/h3&gt;

&lt;p&gt;&lt;code&gt;@TaskLocal&lt;/code&gt; permite acceder a una propiedad dentro de una jerarquía de tareas. O sea que, sin importar el nivel de profundidad dentro de esta jerarquía, siempre que no se haya usado un &lt;code&gt;Task.detached&lt;/code&gt;, se puede acceder a ese &lt;code&gt;TaskLocal&lt;/code&gt;.&lt;/p&gt;




&lt;h2&gt;
  
  
  Recordar sin releer
&lt;/h2&gt;

&lt;h3&gt;
  
  
  ¿Puedes explicar con tus propias palabras cómo funciona el flujo completo de un "Test Scoping Trait"?
&lt;/h3&gt;

&lt;h3&gt;
  
  
  ¿Cuál es la diferencia práctica entre aplicar un &lt;code&gt;trait&lt;/code&gt; a un &lt;code&gt;@Test&lt;/code&gt; individual versus a un &lt;code&gt;@Suite&lt;/code&gt;?
&lt;/h3&gt;

&lt;h3&gt;
  
  
  ¿Por qué es obligatorio usar &lt;code&gt;await&lt;/code&gt; dentro del closure de &lt;code&gt;confirmation()&lt;/code&gt;?
&lt;/h3&gt;




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

&lt;h3&gt;
  
  
  ¿Qué ventajas concretas aporta Swift Testing sobre XCTest para código concurrente?
&lt;/h3&gt;

&lt;h3&gt;
  
  
  ¿En qué escenarios usarías Test Scoping Traits en lugar de simplemente usar init/deinit?
&lt;/h3&gt;

&lt;h3&gt;
  
  
  ¿Qué limitaciones tiene aún Swift Testing según el artículo?
&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] Probando código concurrente con XCTest</title>
      <dc:creator>GoyesDev</dc:creator>
      <pubDate>Wed, 13 May 2026 11:15:10 +0000</pubDate>
      <link>https://dev.to/david_goyes_a488f58a17a53/sc-probando-codigo-concurrente-con-xctest-180k</link>
      <guid>https://dev.to/david_goyes_a488f58a17a53/sc-probando-codigo-concurrente-con-xctest-180k</guid>
      <description>&lt;h2&gt;
  
  
  Comprensión durante la lectura
&lt;/h2&gt;

&lt;h3&gt;
  
  
  ¿Por qué es difícil escribir tests para código asíncrono?
&lt;/h3&gt;

&lt;p&gt;Si las pruebas para código asíncrono no están bien hechas, puede ser que funcionen por coincidencia, dando la falsa idea de que el código es seguro.&lt;/p&gt;

&lt;h3&gt;
  
  
  ¿Qué son los "flaky tests" y cómo se pueden evitar?
&lt;/h3&gt;

&lt;p&gt;Un "flaky test" es una prueba que funciona algunas veces, y otras no.&lt;/p&gt;

&lt;h3&gt;
  
  
  ¿Qué desafíos introduce &lt;code&gt;@MainActor&lt;/code&gt; al momento de hacer tests?
&lt;/h3&gt;

&lt;p&gt;Si una clase o método de producción está aislado en &lt;code&gt;MainActor&lt;/code&gt;, la prueba (o clase de prueba) puede hacer &lt;code&gt;await&lt;/code&gt; para hacer el cambio de dominio de aislamiento, o también puede ser marcada con &lt;code&gt;@MainActor&lt;/code&gt;. No obstante, esto último implicaría que las pruebas (o clase de prueba) marcadas con &lt;code&gt;@MainActor&lt;/code&gt; se ejecutan de forma serial.&lt;/p&gt;

&lt;p&gt;Ante esta problemática, se recomienda extraer el comportamiento en otra clase que no esté marcada con &lt;code&gt;@MainActor&lt;/code&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  ¿Cómo se puede esperar a que una tarea asíncrona complete dentro de un test?
&lt;/h3&gt;

&lt;p&gt;Un método &lt;code&gt;async&lt;/code&gt; puede esperarse con &lt;code&gt;await&lt;/code&gt; directamente, y poniendo &lt;code&gt;async&lt;/code&gt; en la firma de la prueba.&lt;/p&gt;

&lt;h3&gt;
  
  
  ¿Por qué no se puede usar &lt;code&gt;wait(for:)&lt;/code&gt; en contextos de concurrencia?
&lt;/h3&gt;

&lt;p&gt;Los métodos normales para esperar por un &lt;code&gt;XCTExpectation&lt;/code&gt; no están diseñados para trabajar en un ambiente concurrente. Por esta razón, se debe usar en su lugar &lt;a href="https://developer.apple.com/documentation/xctest/xctestcase/fulfillment(of:timeout:enforceorder:)" rel="noopener noreferrer"&gt;&lt;code&gt;fulfillment(of:timeout:enforceOrder:)&lt;/code&gt;&lt;/a&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  ¿Qué es el "System Under Test" (SUT)?
&lt;/h3&gt;

&lt;p&gt;"SUT" es una convención de nombre para referirse a la clase que va a ser probada.&lt;/p&gt;

&lt;h3&gt;
  
  
  ¿Por qué falla el test con &lt;code&gt;searchWithSearchTask&lt;/code&gt; aunque el código se vea correcto?
&lt;/h3&gt;

&lt;p&gt;Internamente tiene un &lt;code&gt;try await Task.sleep(for: .milliseconds(500))&lt;/code&gt;. Como inicialmente se construyó la prueba como si fuera síncrona, esto no daba tiempo al código de producción para ejecutar el &lt;code&gt;sleep&lt;/code&gt; y terminar adecuadamente.&lt;/p&gt;




&lt;h2&gt;
  
  
  Recordar sin releer
&lt;/h2&gt;

&lt;h3&gt;
  
  
  ¿Cómo se usa &lt;code&gt;withObservationTracking&lt;/code&gt; para resolver el problema de esperar resultados?
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Se crea un &lt;code&gt;XCTExpectation&lt;/code&gt;. Por ejemplo: &lt;code&gt;let expectation = self.expectation(description: "\"Search complete\")&lt;/code&gt;"&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Se monitorean cambios en una variable de una clase marcada con &lt;code&gt;@Observable&lt;/code&gt;, o que sea &lt;code&gt;@Published&lt;/code&gt;, con el bloque &lt;a href="https://developer.apple.com/documentation/observation/withobservationtracking(_:onchange:)" rel="noopener noreferrer"&gt;&lt;code&gt;withObservationTracking(_:onChange:)&lt;/code&gt;&lt;/a&gt;. El objetivo es que, ante cualquier cambio de la variable de interés, se haga &lt;a href="https://developer.apple.com/documentation/xctest/xctestexpectation/fulfill()" rel="noopener noreferrer"&gt;&lt;code&gt;fulfill()&lt;/code&gt;&lt;/a&gt; sobre el &lt;code&gt;XCTestExpectation&lt;/code&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Se espera al &lt;code&gt;fulfill()&lt;/code&gt; del &lt;code&gt;XCTExpectation&lt;/code&gt; con &lt;a href="https://developer.apple.com/documentation/xctest/xctestcase/fulfillment(of:timeout:enforceorder:)" rel="noopener noreferrer"&gt;&lt;code&gt;fulfillment(of:timeout:enforceOrder:)&lt;/code&gt;&lt;/a&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Se hacen las validaciones que sean necesarias con &lt;a href="https://developer.apple.com/documentation/xctest/xctassert" rel="noopener noreferrer"&gt;&lt;code&gt;XCTAssert&lt;/code&gt;&lt;/a&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  ¿Cómo se declaran &lt;code&gt;setUp&lt;/code&gt; y &lt;code&gt;tearDown&lt;/code&gt; para soportar código asíncrono?
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://developer.apple.com/documentation/xctest/xctest/setup(completion:)" rel="noopener noreferrer"&gt;&lt;code&gt;func setUp() async throws&lt;/code&gt;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://developer.apple.com/documentation/xctest/xctest/teardown(completion:)" rel="noopener noreferrer"&gt;&lt;code&gt;func tearDown() async throws&lt;/code&gt;&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;




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

&lt;h3&gt;
  
  
  ¿Cuáles son las tres técnicas clave aprendidas para testear código concurrente?
&lt;/h3&gt;

&lt;h3&gt;
  
  
  ¿En qué situaciones usarías &lt;code&gt;@MainActor&lt;/code&gt; en un test y cuál es su costo?
&lt;/h3&gt;

&lt;h3&gt;
  
  
  ¿Qué diferencia hay entre este enfoque y el que ofrece el framework Swift Testing mencionado al final?
&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] sync vs async vs paralelo</title>
      <dc:creator>GoyesDev</dc:creator>
      <pubDate>Tue, 12 May 2026 23:13:32 +0000</pubDate>
      <link>https://dev.to/david_goyes_a488f58a17a53/sc-sync-vs-async-vs-paralelo-46kl</link>
      <guid>https://dev.to/david_goyes_a488f58a17a53/sc-sync-vs-async-vs-paralelo-46kl</guid>
      <description>&lt;h2&gt;
  
  
  Comprensión durante la lectura
&lt;/h2&gt;

&lt;h3&gt;
  
  
  ¿Cuál es el espectro de ejecución propuesto por el autor y en qué orden recomienda transitarlo?
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;Síncrono&lt;/li&gt;
&lt;li&gt;Asíncrono&lt;/li&gt;
&lt;li&gt;Paralelo.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Empezar desde el nivel más bajo y solo avanzar cuando se pruebe que es necesario. Esto evita optimización prematura y mantiene la complejidad baja.&lt;/p&gt;

&lt;h3&gt;
  
  
  ¿Qué criterios determinan que un método es candidato a ejecutarse de forma asíncrona o en paralelo?
&lt;/h3&gt;

&lt;p&gt;Solo si cumple alguna de las siguientes condiciones, se puede pensar en &lt;strong&gt;usar código asíncrono&lt;/strong&gt; (ni siquiera estamos hablando de ejecución en segundo plano).&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;No toca la UI.&lt;/li&gt;
&lt;li&gt;Almacena datos de forma persistente.&lt;/li&gt;
&lt;li&gt;Transforma o procesa conjuntos de datos grandes.&lt;/li&gt;
&lt;li&gt;Se comunica a través de internet.&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  ¿Por qué el autor recomienda empezar siempre con un método sincrónico, incluso cuando la tarea parece pesada?
&lt;/h3&gt;

&lt;p&gt;La mayoría de dispositivos de hoy en día tienen una gran capacidad de cómputo y el código corre muy rápidamente. Saltar a un dominio de aislamiento de segundo plano puede ralentizar el código más de lo que puede optimizarlo.&lt;/p&gt;

&lt;h3&gt;
  
  
  ¿Cómo define el autor el concepto de "carga cognitiva" y por qué lo relaciona con la concurrencia?
&lt;/h3&gt;

&lt;p&gt;Cada capa de concurrencia añade:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Más puntos de suspensión.&lt;/li&gt;
&lt;li&gt;Más estados para entender.&lt;/li&gt;
&lt;li&gt;Más oportunidades para bugs por cancelación.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Por estas razones, si el código se mantiene síncrono, entonces se evita esta carga cognitiva.&lt;/p&gt;

&lt;h3&gt;
  
  
  ¿Qué lista de verificación propone el autor antes de decidir usar ejecución asíncrona o paralela?
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;¿Este código bloquea el &lt;code&gt;MainActor&lt;/code&gt; lo suficiente para que sea visible?&lt;/li&gt;
&lt;li&gt;¿Este trabajo escala con los datos del usuario? (N items -&amp;gt; N costo)&lt;/li&gt;
&lt;li&gt;¿El trabajo involucra I/O?&lt;/li&gt;
&lt;li&gt;¿El trabajo se beneficia de combinar varias operaciones independientes?&lt;/li&gt;
&lt;li&gt;¿Esta lógica se llama con frecuencia?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Si se cumplen 2 o más condiciones, entonces se justifica usar async o paralelismo.&lt;/p&gt;

&lt;h3&gt;
  
  
  ¿Qué costos asocia el autor con la ejecución paralela y cómo afectan a los dispositivos Apple?
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Puede haber un aumento en CPU y memoria.&lt;/li&gt;
&lt;li&gt;Se pueden saturar los recursos del sistema.&lt;/li&gt;
&lt;li&gt;Posible mayor consumo de batería.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  ¿Cómo justifica el autor que la experiencia de usuario (UX) puede motivar el uso del segundo plano incluso cuando el rendimiento no lo exige?
&lt;/h3&gt;

&lt;p&gt;A veces interrumpir la UI por un frame va a hacer sentir al usuario que la aplicación es lenta. En este caso, vale la pena ejecutar en segundo plano incluso aunque el tiempo total aumente ligeramente.&lt;/p&gt;




&lt;h2&gt;
  
  
  Recordar sin releer
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Sin mirar el artículo, ¿cuáles son las tres fases de concurrencia y qué representa cada una?
&lt;/h3&gt;

&lt;h3&gt;
  
  
  ¿Cuántas condiciones de la lista de verificación deben cumplirse para justificar el uso de async/paralelo?
&lt;/h3&gt;

&lt;h3&gt;
  
  
  ¿Qué pregunta clave se hace el autor a sí mismo al considerar si el paralelismo vale la pena?
&lt;/h3&gt;

&lt;h3&gt;
  
  
  Explica con tus propias palabras por qué incluso una operación de 80 ms puede justificar ejecutarse en segundo plano.
&lt;/h3&gt;




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

&lt;h3&gt;
  
  
  ¿En qué situaciones concretas de tu propio código aplicarías el espectro sincrónico → asíncrono → paralelo?
&lt;/h3&gt;

&lt;h3&gt;
  
  
  ¿Estás de acuerdo con la recomendación de empezar siempre con código sincrónico? ¿Qué argumentos a favor o en contra puedes formular?
&lt;/h3&gt;

&lt;h3&gt;
  
  
  ¿Cómo se relaciona el concepto de "optimización prematura" mencionado aquí con principios generales de ingeniería de software que ya conoces?
&lt;/h3&gt;

&lt;h3&gt;
  
  
  ¿Qué limitaciones o contextos en los que el enfoque del autor podría no ser aplicable puedes identificar?
&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>
