<?xml version="1.0" encoding="UTF-8"?><rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>iOS Developer Diary</title>
	<atom:link href="https://iosdeveloperdiary.com/feed/" rel="self" type="application/rss+xml" />
	<link>https://iosdeveloperdiary.com</link>
	<description></description>
	<lastBuildDate>Sun, 12 Apr 2026 17:21:18 +0000</lastBuildDate>
	<language>en-US</language>
	<sy:updatePeriod>
	hourly	</sy:updatePeriod>
	<sy:updateFrequency>
	1	</sy:updateFrequency>
	<generator>https://wordpress.org/?v=7.0.2</generator>

<image>
	<url>https://iosdeveloperdiary.com/wp-content/uploads/2022/07/mini_logo-150x150.png</url>
	<title>iOS Developer Diary</title>
	<link>https://iosdeveloperdiary.com</link>
	<width>32</width>
	<height>32</height>
</image> 
	<item>
		<title>Actor isolation keywords in Swift 6.2 — nonisolated, isolated, @concurrent, @globalActor, any Actor</title>
		<link>https://iosdeveloperdiary.com/actor-isolation-keywords-in-swift-nonisolated-isolated-concurrent-globalactor-any-actor/</link>
		
		<dc:creator><![CDATA[Tomasz]]></dc:creator>
		<pubDate>Sun, 12 Apr 2026 16:56:05 +0000</pubDate>
				<category><![CDATA[Uncategorized]]></category>
		<category><![CDATA[@concurrent]]></category>
		<category><![CDATA[@globalActor]]></category>
		<category><![CDATA[any Actor]]></category>
		<category><![CDATA[isolated]]></category>
		<category><![CDATA[nonisolated]]></category>
		<category><![CDATA[Swift 6.2]]></category>
		<guid isPermaLink="false">https://iosdeveloperdiary.com/?p=495</guid>

					<description><![CDATA[Swift Concurrency has a handful of keywords that control where code runs: nonisolated, isolated, @concurrent, @globalActor. They all answer the same question — which executor does this function run on? — just in different ways. nonisolated [&#8230;]]]></description>
										<content:encoded><![CDATA[		<div data-elementor-type="wp-post" data-elementor-id="495" class="elementor elementor-495" data-elementor-post-type="post">
						<section class="elementor-section elementor-top-section elementor-element elementor-element-234aa71 elementor-section-boxed elementor-section-height-default elementor-section-height-default" data-id="234aa71" data-element_type="section" data-e-type="section">
						<div class="elementor-container elementor-column-gap-default">
					<div class="elementor-column elementor-col-100 elementor-top-column elementor-element elementor-element-0ee126c" data-id="0ee126c" data-element_type="column" data-e-type="column">
			<div class="elementor-widget-wrap elementor-element-populated">
						<div class="elementor-element elementor-element-0c0d825 elementor-widget__width-initial elementor-widget elementor-widget-text-editor" data-id="0c0d825" data-element_type="widget" data-e-type="widget" data-widget_type="text-editor.default">
				<div class="elementor-widget-container">
									<p><span style="color: #141413; font-family: 'Anthropic Sans', sans-serif; font-size: 15px; font-variant-ligatures: normal;">Swift Concurrency has a handful of keywords that control where code runs: </span><code style="margin: 0px; padding: 1px 5px; font-family: ui-monospace, monospace; font-size: 13px; background: 0% 0% repeat #f5f4ed; border-radius: 4px; color: #141413; font-variant-ligatures: normal;">nonisolated</code><span style="color: #141413; font-family: 'Anthropic Sans', sans-serif; font-size: 15px; font-variant-ligatures: normal;">, </span><code style="margin: 0px; padding: 1px 5px; font-family: ui-monospace, monospace; font-size: 13px; background: 0% 0% repeat #f5f4ed; border-radius: 4px; color: #141413; font-variant-ligatures: normal;">isolated</code><span style="color: #141413; font-family: 'Anthropic Sans', sans-serif; font-size: 15px; font-variant-ligatures: normal;">, </span><code style="margin: 0px; padding: 1px 5px; font-family: ui-monospace, monospace; font-size: 13px; background: 0% 0% repeat #f5f4ed; border-radius: 4px; color: #141413; font-variant-ligatures: normal;">@concurrent</code><span style="color: #141413; font-family: 'Anthropic Sans', sans-serif; font-size: 15px; font-variant-ligatures: normal;">, </span><code style="margin: 0px; padding: 1px 5px; font-family: ui-monospace, monospace; font-size: 13px; background: 0% 0% repeat #f5f4ed; border-radius: 4px; color: #141413; font-variant-ligatures: normal;">@globalActor</code><span style="color: #141413; font-family: 'Anthropic Sans', sans-serif; font-size: 15px; font-variant-ligatures: normal;">. They all answer the same question — </span><em style="margin: 0px; padding: 0px; color: #141413; font-family: 'Anthropic Sans', sans-serif; font-size: 15px; font-variant-ligatures: normal;">which executor does this function run on?</em><span style="color: #141413; font-family: 'Anthropic Sans', sans-serif; font-size: 15px; font-variant-ligatures: normal;"> — just in different ways.</span></p>								</div>
				</div>
					</div>
		</div>
					</div>
		</section>
				<section class="elementor-section elementor-top-section elementor-element elementor-element-9050e6a elementor-section-boxed elementor-section-height-default elementor-section-height-default" data-id="9050e6a" data-element_type="section" data-e-type="section">
						<div class="elementor-container elementor-column-gap-default">
					<div class="elementor-column elementor-col-100 elementor-top-column elementor-element elementor-element-f3356c6" data-id="f3356c6" data-element_type="column" data-e-type="column">
			<div class="elementor-widget-wrap elementor-element-populated">
						<div class="elementor-element elementor-element-dea5f8e elementor-widget-divider--view-line elementor-widget elementor-widget-divider" data-id="dea5f8e" data-element_type="widget" data-e-type="widget" data-widget_type="divider.default">
				<div class="elementor-widget-container">
							<div class="elementor-divider">
			<span class="elementor-divider-separator">
						</span>
		</div>
						</div>
				</div>
					</div>
		</div>
					</div>
		</section>
				<section class="elementor-section elementor-top-section elementor-element elementor-element-39dd11c elementor-section-boxed elementor-section-height-default elementor-section-height-default" data-id="39dd11c" data-element_type="section" data-e-type="section">
						<div class="elementor-container elementor-column-gap-default">
					<div class="elementor-column elementor-col-100 elementor-top-column elementor-element elementor-element-79b8259" data-id="79b8259" data-element_type="column" data-e-type="column">
			<div class="elementor-widget-wrap elementor-element-populated">
						<div class="elementor-element elementor-element-d8d6c52 elementor-widget elementor-widget-heading" data-id="d8d6c52" data-element_type="widget" data-e-type="widget" data-widget_type="heading.default">
				<div class="elementor-widget-container">
					<h1 class="elementor-heading-title elementor-size-default"><b><span style="white-space: normal;margin: 2.2rem 0px 0.8rem;padding: 0px;font-size: 19px;font-family: &quot;Anthropic Sans&quot;, sans-serif">nonisolated — run on the caller's executor</span></b></h1>				</div>
				</div>
				<div class="elementor-element elementor-element-82adec3 elementor-widget elementor-widget-text-editor" data-id="82adec3" data-element_type="widget" data-e-type="widget" data-widget_type="text-editor.default">
				<div class="elementor-widget-container">
									<p><span style="color: #141413; font-family: 'Anthropic Sans', sans-serif; font-size: 15px; font-variant-ligatures: normal;">When you mark a function </span><code style="margin: 0px; padding: 1px 5px; font-family: ui-monospace, monospace; font-size: 13px; background: 0% 0% repeat #f5f4ed; border-radius: 4px; color: #141413; font-variant-ligatures: normal;">nonisolated</code><span style="color: #141413; font-family: 'Anthropic Sans', sans-serif; font-size: 15px; font-variant-ligatures: normal;"> inside an actor, it doesn&#8217;t hop off to some generic executor. With </span><strong style="margin: 0px; padding: 0px; color: #141413; font-family: 'Anthropic Sans', sans-serif; font-size: 15px; font-variant-ligatures: normal;">Approachable Concurrency</strong><span style="color: #141413; font-family: 'Anthropic Sans', sans-serif; font-size: 15px; font-variant-ligatures: normal;"> enabled (default from Swift 6.2, opt-in via </span><code style="margin: 0px; padding: 1px 5px; font-family: ui-monospace, monospace; font-size: 13px; background: 0% 0% repeat #f5f4ed; border-radius: 4px; color: #141413; font-variant-ligatures: normal;">SWIFT_UPCOMING_FEATURE_APPROACHABLE_CONCURRENCY = YES</code><span style="color: #141413; font-family: 'Anthropic Sans', sans-serif; font-size: 15px; font-variant-ligatures: normal;"> in earlier versions), a </span><code style="margin: 0px; padding: 1px 5px; font-family: ui-monospace, monospace; font-size: 13px; background: 0% 0% repeat #f5f4ed; border-radius: 4px; color: #141413; font-variant-ligatures: normal;">nonisolated</code><span style="color: #141413; font-family: 'Anthropic Sans', sans-serif; font-size: 15px; font-variant-ligatures: normal;"> function runs on the </span><em style="margin: 0px; padding: 0px; color: #141413; font-family: 'Anthropic Sans', sans-serif; font-size: 15px; font-variant-ligatures: normal;">caller&#8217;s</em><span style="color: #141413; font-family: 'Anthropic Sans', sans-serif; font-size: 15px; font-variant-ligatures: normal;"> executor instead.</span></p>								</div>
				</div>
					</div>
		</div>
					</div>
		</section>
				<section class="elementor-section elementor-top-section elementor-element elementor-element-7c459ff elementor-section-boxed elementor-section-height-default elementor-section-height-default" data-id="7c459ff" data-element_type="section" data-e-type="section">
						<div class="elementor-container elementor-column-gap-default">
					<div class="elementor-column elementor-col-100 elementor-top-column elementor-element elementor-element-5d6e8d3" data-id="5d6e8d3" data-element_type="column" data-e-type="column">
			<div class="elementor-widget-wrap elementor-element-populated">
						<div class="elementor-element elementor-element-9f061a1 elementor-widget elementor-widget-text-editor" data-id="9f061a1" data-element_type="widget" data-e-type="widget" data-widget_type="text-editor.default">
				<div class="elementor-widget-container">
									<blockquote>
<h6><i>This was the original Swift Concurrency behaviour. SE-0338 changed it so that nonisolated async functions always ran off-actor. That change was later reverted in Swift 6.2 — so we&#8217;re back to running on the caller&#8217;s executor. nonisolated is now equivalent to nonisolated(nonsending).</i></h6>
</blockquote>								</div>
				</div>
					</div>
		</div>
					</div>
		</section>
				<section class="elementor-section elementor-top-section elementor-element elementor-element-25b200c elementor-section-boxed elementor-section-height-default elementor-section-height-default" data-id="25b200c" data-element_type="section" data-e-type="section">
						<div class="elementor-container elementor-column-gap-default">
					<div class="elementor-column elementor-col-100 elementor-top-column elementor-element elementor-element-e09d4c3" data-id="e09d4c3" data-element_type="column" data-e-type="column">
			<div class="elementor-widget-wrap elementor-element-populated">
						<div class="elementor-element elementor-element-328d87a elementor-widget elementor-widget-code-highlight" data-id="328d87a" data-element_type="widget" data-e-type="widget" data-widget_type="code-highlight.default">
				<div class="elementor-widget-container">
							<div class="prismjs-default copy-to-clipboard ">
			<pre data-line="" class="highlight-height language-swift ">
				<code readonly="true" class="language-swift">
					<xmp>actor MyActor {
  var value = "abc"

  func test() async {
    await nonisolatedFuncCalledFromSelfActor()

    Task { @MainActor in
      await nonisolatedFuncCalledFromMainActor()
    }
  }

  nonisolated func nonisolatedFuncCalledFromSelfActor() async {
    self.assertIsolated() // ✓ — runs on MyActor's executor
    // self.value = "x"  ← ✗ compiler still sees this as nonisolated
  }

  nonisolated func nonisolatedFuncCalledFromMainActor() async {
    MainActor.assertIsolated() // ✓ — caller was @MainActor
  }
}</xmp>
				</code>
			</pre>
		</div>
						</div>
				</div>
					</div>
		</div>
					</div>
		</section>
				<section class="elementor-section elementor-top-section elementor-element elementor-element-29b168b elementor-section-boxed elementor-section-height-default elementor-section-height-default" data-id="29b168b" data-element_type="section" data-e-type="section">
						<div class="elementor-container elementor-column-gap-default">
					<div class="elementor-column elementor-col-100 elementor-top-column elementor-element elementor-element-5e776dc" data-id="5e776dc" data-element_type="column" data-e-type="column">
			<div class="elementor-widget-wrap elementor-element-populated">
						<div class="elementor-element elementor-element-98b5d34 elementor-widget elementor-widget-text-editor" data-id="98b5d34" data-element_type="widget" data-e-type="widget" data-widget_type="text-editor.default">
				<div class="elementor-widget-container">
									<p style="margin-bottom: 1.2rem; padding: 0px; font-size: 15px; color: #141413; line-height: 1.8; font-family: 'Anthropic Sans', sans-serif; font-variant-ligatures: normal;">Notice the catch: even though <code style="margin: 0px; padding: 1px 5px; font-family: ui-monospace, monospace; font-size: 13px; background: 0% 0% repeat #f5f4ed; border-radius: 4px;">assertIsolated()</code> passes, the compiler still treats the function as nonisolated at the type-system level, so you can&#8217;t touch actor-isolated properties. The runtime and the type system are telling you different things — <code style="margin: 0px; padding: 1px 5px; font-family: ui-monospace, monospace; font-size: 13px; background: 0% 0% repeat #f5f4ed; border-radius: 4px;">nonisolated</code> describes the <em style="margin: 0px; padding: 0px;">static view</em>, not what&#8217;s actually happening on the thread.</p><p style="margin-bottom: 1.2rem; padding: 0px; font-size: 15px; color: #141413; line-height: 1.8; font-family: 'Anthropic Sans', sans-serif; font-variant-ligatures: normal;">Why is this useful? Less hopping on and off executors. Every unnecessary hop is overhead — the function suspends, waits for the target executor, and resumes. If the caller is already on the right executor, <code style="margin: 0px; padding: 1px 5px; font-family: ui-monospace, monospace; font-size: 13px; background: 0% 0% repeat #f5f4ed; border-radius: 4px;">nonisolated</code> avoids all of that.</p>								</div>
				</div>
					</div>
		</div>
					</div>
		</section>
				<section class="elementor-section elementor-top-section elementor-element elementor-element-8993b99 elementor-section-boxed elementor-section-height-default elementor-section-height-default" data-id="8993b99" data-element_type="section" data-e-type="section">
						<div class="elementor-container elementor-column-gap-default">
					<div class="elementor-column elementor-col-100 elementor-top-column elementor-element elementor-element-99a8900" data-id="99a8900" data-element_type="column" data-e-type="column">
			<div class="elementor-widget-wrap elementor-element-populated">
						<div class="elementor-element elementor-element-c091cfd elementor-widget-divider--view-line elementor-widget elementor-widget-divider" data-id="c091cfd" data-element_type="widget" data-e-type="widget" data-widget_type="divider.default">
				<div class="elementor-widget-container">
							<div class="elementor-divider">
			<span class="elementor-divider-separator">
						</span>
		</div>
						</div>
				</div>
					</div>
		</div>
					</div>
		</section>
				<section class="elementor-section elementor-top-section elementor-element elementor-element-3ba1ac8 elementor-section-boxed elementor-section-height-default elementor-section-height-default" data-id="3ba1ac8" data-element_type="section" data-e-type="section">
						<div class="elementor-container elementor-column-gap-default">
					<div class="elementor-column elementor-col-100 elementor-top-column elementor-element elementor-element-64d8e5a" data-id="64d8e5a" data-element_type="column" data-e-type="column">
			<div class="elementor-widget-wrap elementor-element-populated">
						<div class="elementor-element elementor-element-0b63948 elementor-widget elementor-widget-heading" data-id="0b63948" data-element_type="widget" data-e-type="widget" data-widget_type="heading.default">
				<div class="elementor-widget-container">
					<h1 class="elementor-heading-title elementor-size-default"><b><span style="white-space: normal;margin: 2.2rem 0px 0.8rem;padding: 0px;font-size: 19px;font-family: &quot;Anthropic Sans&quot;, sans-serif">@concurrent — force a hop off the actor</span></b></h1>				</div>
				</div>
				<div class="elementor-element elementor-element-b5d4d14 elementor-widget elementor-widget-text-editor" data-id="b5d4d14" data-element_type="widget" data-e-type="widget" data-widget_type="text-editor.default">
				<div class="elementor-widget-container">
									<p><span style="color: #141413; font-family: 'Anthropic Sans', sans-serif; font-size: 15px; font-variant-ligatures: normal;">Sometimes you want the opposite — explicitly force the function off the actor and onto the global concurrent executor, regardless of who called it. That&#8217;s what </span><code style="margin: 0px; padding: 1px 5px; font-family: ui-monospace, monospace; font-size: 13px; background: 0% 0% repeat #f5f4ed; border-radius: 4px; color: #141413; font-variant-ligatures: normal;">@concurrent</code><span style="color: #141413; font-family: 'Anthropic Sans', sans-serif; font-size: 15px; font-variant-ligatures: normal;"> is for.</span></p>								</div>
				</div>
					</div>
		</div>
					</div>
		</section>
				<section class="elementor-section elementor-top-section elementor-element elementor-element-e9ed6a6 elementor-section-boxed elementor-section-height-default elementor-section-height-default" data-id="e9ed6a6" data-element_type="section" data-e-type="section">
						<div class="elementor-container elementor-column-gap-default">
					<div class="elementor-column elementor-col-100 elementor-top-column elementor-element elementor-element-9c6f7cd" data-id="9c6f7cd" data-element_type="column" data-e-type="column">
			<div class="elementor-widget-wrap elementor-element-populated">
						<div class="elementor-element elementor-element-413afd0 elementor-widget elementor-widget-code-highlight" data-id="413afd0" data-element_type="widget" data-e-type="widget" data-widget_type="code-highlight.default">
				<div class="elementor-widget-container">
							<div class="prismjs-default  ">
			<pre data-line="" class="highlight-height language-swift line-numbers">
				<code readonly="true" class="language-swift">
					<xmp>actor MyActor {
  // Always hops to global concurrent executor
  @concurrent nonisolated func concurrentNonisolatedFuncCalledFromSelfActor() async {
    // self.assertIsolated() ← ✗ not on MyActor's executor
  }

  // @concurrent automatically marks the func as nonisolated too
  @concurrent func concurrentFuncCalledFromSelfActor() async {
    // self.assertIsolated() ← ✗ not on MyActor's executor
  }
}</xmp>
				</code>
			</pre>
		</div>
						</div>
				</div>
					</div>
		</div>
					</div>
		</section>
				<section class="elementor-section elementor-top-section elementor-element elementor-element-255034c elementor-section-boxed elementor-section-height-default elementor-section-height-default" data-id="255034c" data-element_type="section" data-e-type="section">
						<div class="elementor-container elementor-column-gap-default">
					<div class="elementor-column elementor-col-100 elementor-top-column elementor-element elementor-element-2fd4af2" data-id="2fd4af2" data-element_type="column" data-e-type="column">
			<div class="elementor-widget-wrap elementor-element-populated">
						<div class="elementor-element elementor-element-496d47f elementor-widget-divider--view-line elementor-widget elementor-widget-divider" data-id="496d47f" data-element_type="widget" data-e-type="widget" data-widget_type="divider.default">
				<div class="elementor-widget-container">
							<div class="elementor-divider">
			<span class="elementor-divider-separator">
						</span>
		</div>
						</div>
				</div>
					</div>
		</div>
					</div>
		</section>
				<section class="elementor-section elementor-top-section elementor-element elementor-element-411ebf7 elementor-section-boxed elementor-section-height-default elementor-section-height-default" data-id="411ebf7" data-element_type="section" data-e-type="section">
						<div class="elementor-container elementor-column-gap-default">
					<div class="elementor-column elementor-col-100 elementor-top-column elementor-element elementor-element-60d7d24" data-id="60d7d24" data-element_type="column" data-e-type="column">
			<div class="elementor-widget-wrap elementor-element-populated">
						<div class="elementor-element elementor-element-ead0311 elementor-widget elementor-widget-heading" data-id="ead0311" data-element_type="widget" data-e-type="widget" data-widget_type="heading.default">
				<div class="elementor-widget-container">
					<h1 class="elementor-heading-title elementor-size-default"><b><span style="white-space: normal;margin: 2.2rem 0px 0.8rem;padding: 0px;font-size: 19px;font-family: &quot;Anthropic Sans&quot;, sans-serif">isolated parameter — borrow another actor's isolation</span></b></h1>				</div>
				</div>
				<div class="elementor-element elementor-element-aa112a3 elementor-widget elementor-widget-text-editor" data-id="aa112a3" data-element_type="widget" data-e-type="widget" data-widget_type="text-editor.default">
				<div class="elementor-widget-container">
									<p><span style="color: #141413; font-family: 'Anthropic Sans', sans-serif; font-size: 15px; font-variant-ligatures: normal;">Putting </span><code style="margin: 0px; padding: 1px 5px; font-family: ui-monospace, monospace; font-size: 13px; background: 0% 0% repeat #f5f4ed; border-radius: 4px; color: #141413; font-variant-ligatures: normal;">isolated</code><span style="color: #141413; font-family: 'Anthropic Sans', sans-serif; font-size: 15px; font-variant-ligatures: normal;"> before a parameter transfers the function&#8217;s isolation to that actor. The function is no longer isolated to </span><code style="margin: 0px; padding: 1px 5px; font-family: ui-monospace, monospace; font-size: 13px; background: 0% 0% repeat #f5f4ed; border-radius: 4px; color: #141413; font-variant-ligatures: normal;">self</code><span style="color: #141413; font-family: 'Anthropic Sans', sans-serif; font-size: 15px; font-variant-ligatures: normal;"> — it runs on the actor passed as an argument.</span></p>								</div>
				</div>
					</div>
		</div>
					</div>
		</section>
				<section class="elementor-section elementor-top-section elementor-element elementor-element-303bddf elementor-section-boxed elementor-section-height-default elementor-section-height-default" data-id="303bddf" data-element_type="section" data-e-type="section">
						<div class="elementor-container elementor-column-gap-default">
					<div class="elementor-column elementor-col-100 elementor-top-column elementor-element elementor-element-ebf5d03" data-id="ebf5d03" data-element_type="column" data-e-type="column">
			<div class="elementor-widget-wrap elementor-element-populated">
						<div class="elementor-element elementor-element-8fcc5f3 elementor-widget elementor-widget-code-highlight" data-id="8fcc5f3" data-element_type="widget" data-e-type="widget" data-widget_type="code-highlight.default">
				<div class="elementor-widget-container">
							<div class="prismjs-default copy-to-clipboard ">
			<pre data-line="" class="highlight-height language-swift ">
				<code readonly="true" class="language-swift">
					<xmp>actor ActorA {
  var x = "abc"

  func test() async {
    let b = ActorB()

    // Must await — needs to hop to b's executor
    await changeOtherActorStateWithIsolationToOtherActor(b)

    // No await — already on self's executor
    changeOtherActorStateWithSelfActorIsolation(b)
  }

  // Isolated to b, NOT to self
  func changeOtherActorStateWithIsolationToOtherActor(_ b: isolated ActorB) {
    b.y = "new"        // ✓
    // self.x = "new"  ← ✗ no longer isolated to self
  }

  // Isolated to self, b is just a regular parameter
  func changeOtherActorStateWithSelfActorIsolation(_ b: ActorB) {
    x = "new"          // ✓
  }
}</xmp>
				</code>
			</pre>
		</div>
						</div>
				</div>
					</div>
		</div>
					</div>
		</section>
				<section class="elementor-section elementor-top-section elementor-element elementor-element-02da476 elementor-section-boxed elementor-section-height-default elementor-section-height-default" data-id="02da476" data-element_type="section" data-e-type="section">
						<div class="elementor-container elementor-column-gap-default">
					<div class="elementor-column elementor-col-100 elementor-top-column elementor-element elementor-element-d954d7b" data-id="d954d7b" data-element_type="column" data-e-type="column">
			<div class="elementor-widget-wrap elementor-element-populated">
						<div class="elementor-element elementor-element-dc2a366 elementor-widget elementor-widget-text-editor" data-id="dc2a366" data-element_type="widget" data-e-type="widget" data-widget_type="text-editor.default">
				<div class="elementor-widget-container">
									<p><span style="color: #141413; font-family: 'Anthropic Sans', sans-serif; font-size: 15px; font-variant-ligatures: normal;">Only one parameter per function can be marked </span><code style="margin: 0px; padding: 1px 5px; font-family: ui-monospace, monospace; font-size: 13px; background: 0% 0% repeat #f5f4ed; border-radius: 4px; color: #141413; font-variant-ligatures: normal;">isolated</code><span style="color: #141413; font-family: 'Anthropic Sans', sans-serif; font-size: 15px; font-variant-ligatures: normal;">.</span></p>								</div>
				</div>
					</div>
		</div>
					</div>
		</section>
				<section class="elementor-section elementor-top-section elementor-element elementor-element-fafd3c2 elementor-section-boxed elementor-section-height-default elementor-section-height-default" data-id="fafd3c2" data-element_type="section" data-e-type="section">
						<div class="elementor-container elementor-column-gap-default">
					<div class="elementor-column elementor-col-100 elementor-top-column elementor-element elementor-element-ece9318" data-id="ece9318" data-element_type="column" data-e-type="column">
			<div class="elementor-widget-wrap elementor-element-populated">
						<div class="elementor-element elementor-element-4f057a2 elementor-widget-divider--view-line elementor-widget elementor-widget-divider" data-id="4f057a2" data-element_type="widget" data-e-type="widget" data-widget_type="divider.default">
				<div class="elementor-widget-container">
							<div class="elementor-divider">
			<span class="elementor-divider-separator">
						</span>
		</div>
						</div>
				</div>
					</div>
		</div>
					</div>
		</section>
				<section class="elementor-section elementor-top-section elementor-element elementor-element-3bfbec3 elementor-section-boxed elementor-section-height-default elementor-section-height-default" data-id="3bfbec3" data-element_type="section" data-e-type="section">
						<div class="elementor-container elementor-column-gap-default">
					<div class="elementor-column elementor-col-100 elementor-top-column elementor-element elementor-element-e40b4ef" data-id="e40b4ef" data-element_type="column" data-e-type="column">
			<div class="elementor-widget-wrap elementor-element-populated">
						<div class="elementor-element elementor-element-c1de006 elementor-widget elementor-widget-heading" data-id="c1de006" data-element_type="widget" data-e-type="widget" data-widget_type="heading.default">
				<div class="elementor-widget-container">
					<h1 class="elementor-heading-title elementor-size-default"><b><span style="white-space: normal;margin: 2.2rem 0px 0.8rem;padding: 0px;font-size: 19px;font-family: &quot;Anthropic Sans&quot;, sans-serif">isolated (any Actor) and #isolation</span></b></h1>				</div>
				</div>
				<div class="elementor-element elementor-element-5d10b4c elementor-widget elementor-widget-text-editor" data-id="5d10b4c" data-element_type="widget" data-e-type="widget" data-widget_type="text-editor.default">
				<div class="elementor-widget-container">
									<p><span style="color: #141413; font-family: 'Anthropic Sans', sans-serif; font-size: 15px; font-variant-ligatures: normal;">You can take it further and write functions that work with </span><em style="margin: 0px; padding: 0px; color: #141413; font-family: 'Anthropic Sans', sans-serif; font-size: 15px; font-variant-ligatures: normal;">any</em><span style="color: #141413; font-family: 'Anthropic Sans', sans-serif; font-size: 15px; font-variant-ligatures: normal;"> actor dynamically. And with </span><code style="margin: 0px; padding: 1px 5px; font-family: ui-monospace, monospace; font-size: 13px; background: 0% 0% repeat #f5f4ed; border-radius: 4px; color: #141413; font-variant-ligatures: normal;">#isolation</code><span style="color: #141413; font-family: 'Anthropic Sans', sans-serif; font-size: 15px; font-variant-ligatures: normal;">, the caller&#8217;s actor is captured automatically at the call site — no need to pass it explicitly.</span></p>								</div>
				</div>
					</div>
		</div>
					</div>
		</section>
				<section class="elementor-section elementor-top-section elementor-element elementor-element-a4e7187 elementor-section-boxed elementor-section-height-default elementor-section-height-default" data-id="a4e7187" data-element_type="section" data-e-type="section">
						<div class="elementor-container elementor-column-gap-default">
					<div class="elementor-column elementor-col-100 elementor-top-column elementor-element elementor-element-6cee7a4" data-id="6cee7a4" data-element_type="column" data-e-type="column">
			<div class="elementor-widget-wrap elementor-element-populated">
						<div class="elementor-element elementor-element-d7ca9a8 elementor-widget elementor-widget-code-highlight" data-id="d7ca9a8" data-element_type="widget" data-e-type="widget" data-widget_type="code-highlight.default">
				<div class="elementor-widget-container">
							<div class="prismjs-default copy-to-clipboard ">
			<pre data-line="" class="highlight-height language-swift ">
				<code readonly="true" class="language-swift">
					<xmp>// #isolation captures the caller's actor at the call site
func changeIsolatedActorVariableWithDefaultIsolatedAny(
  isolation: isolated (any Actor) = #isolation
) {
  if let a = isolation as? MyActor {
    // Compiler doesn't know the dynamic type, so we assert it
    a.assumeIsolated { isolated in
      isolated.value = "abc" // ✓
    }
  }
}

actor Caller {
  func go() {
    changeIsolatedActorVariableWithDefaultIsolatedAny() // isolation = self, no await
  }
}</xmp>
				</code>
			</pre>
		</div>
						</div>
				</div>
					</div>
		</div>
					</div>
		</section>
				<section class="elementor-section elementor-top-section elementor-element elementor-element-ff27865 elementor-section-boxed elementor-section-height-default elementor-section-height-default" data-id="ff27865" data-element_type="section" data-e-type="section">
						<div class="elementor-container elementor-column-gap-default">
					<div class="elementor-column elementor-col-100 elementor-top-column elementor-element elementor-element-a8404ce" data-id="a8404ce" data-element_type="column" data-e-type="column">
			<div class="elementor-widget-wrap elementor-element-populated">
						<div class="elementor-element elementor-element-54b1abe elementor-widget elementor-widget-text-editor" data-id="54b1abe" data-element_type="widget" data-e-type="widget" data-widget_type="text-editor.default">
				<div class="elementor-widget-container">
									<p><code style="margin: 0px; padding: 1px 5px; font-family: ui-monospace, monospace; font-size: 13px; background: 0% 0% repeat #f5f4ed; border-radius: 4px; color: #141413; font-variant-ligatures: normal;">#isolation</code><span style="color: #141413; font-family: 'Anthropic Sans', sans-serif; font-size: 15px; font-variant-ligatures: normal;"> is a compiler macro — it captures the surrounding isolation at the call site, not at the function definition.</span></p>								</div>
				</div>
					</div>
		</div>
					</div>
		</section>
				<section class="elementor-section elementor-top-section elementor-element elementor-element-75265d3 elementor-section-boxed elementor-section-height-default elementor-section-height-default" data-id="75265d3" data-element_type="section" data-e-type="section">
						<div class="elementor-container elementor-column-gap-default">
					<div class="elementor-column elementor-col-100 elementor-top-column elementor-element elementor-element-10adfbd" data-id="10adfbd" data-element_type="column" data-e-type="column">
			<div class="elementor-widget-wrap elementor-element-populated">
						<div class="elementor-element elementor-element-0574bfc elementor-widget-divider--view-line elementor-widget elementor-widget-divider" data-id="0574bfc" data-element_type="widget" data-e-type="widget" data-widget_type="divider.default">
				<div class="elementor-widget-container">
							<div class="elementor-divider">
			<span class="elementor-divider-separator">
						</span>
		</div>
						</div>
				</div>
					</div>
		</div>
					</div>
		</section>
				<section class="elementor-section elementor-top-section elementor-element elementor-element-0fec1bd elementor-section-boxed elementor-section-height-default elementor-section-height-default" data-id="0fec1bd" data-element_type="section" data-e-type="section">
						<div class="elementor-container elementor-column-gap-default">
					<div class="elementor-column elementor-col-100 elementor-top-column elementor-element elementor-element-d843cc8" data-id="d843cc8" data-element_type="column" data-e-type="column">
			<div class="elementor-widget-wrap elementor-element-populated">
						<div class="elementor-element elementor-element-ad7f940 elementor-widget elementor-widget-heading" data-id="ad7f940" data-element_type="widget" data-e-type="widget" data-widget_type="heading.default">
				<div class="elementor-widget-container">
					<h1 class="elementor-heading-title elementor-size-default"><b><span style="white-space: normal;margin: 2.2rem 0px 0.8rem;padding: 0px;font-size: 19px;font-family: &quot;Anthropic Sans&quot;, sans-serif">@globalActor — a shared singleton actor</span></b></h1>				</div>
				</div>
				<div class="elementor-element elementor-element-177339d elementor-widget elementor-widget-text-editor" data-id="177339d" data-element_type="widget" data-e-type="widget" data-widget_type="text-editor.default">
				<div class="elementor-widget-container">
									<p><code style="margin: 0px; padding: 1px 5px; font-family: ui-monospace, monospace; font-size: 13px; background: 0% 0% repeat #f5f4ed; border-radius: 4px; color: #141413; font-variant-ligatures: normal;">@MainActor</code><span style="color: #141413; font-family: 'Anthropic Sans', sans-serif; font-size: 15px; font-variant-ligatures: normal;"> is the most familiar example of a global actor, but you can define your own. A global actor is a singleton actor that multiple types can all be isolated to — since they share the same executor, they can access each other&#8217;s state directly without awaiting.</span></p>								</div>
				</div>
					</div>
		</div>
					</div>
		</section>
				<section class="elementor-section elementor-top-section elementor-element elementor-element-a49f28f elementor-section-boxed elementor-section-height-default elementor-section-height-default" data-id="a49f28f" data-element_type="section" data-e-type="section">
						<div class="elementor-container elementor-column-gap-default">
					<div class="elementor-column elementor-col-100 elementor-top-column elementor-element elementor-element-12670e7" data-id="12670e7" data-element_type="column" data-e-type="column">
			<div class="elementor-widget-wrap elementor-element-populated">
						<div class="elementor-element elementor-element-627de6c elementor-widget elementor-widget-code-highlight" data-id="627de6c" data-element_type="widget" data-e-type="widget" data-widget_type="code-highlight.default">
				<div class="elementor-widget-container">
							<div class="prismjs-default copy-to-clipboard ">
			<pre data-line="" class="highlight-height language-swift ">
				<code readonly="true" class="language-swift">
					<xmp>// Defining a new global actor
@globalActor
actor DatabaseActor {
  static let shared = DatabaseActor()
}

// Both classes share the same actor — they can access each other freely
@DatabaseActor class Repository {
  var cache: [String] = []
}

@DatabaseActor class QueryService {
  func invalidate(_ repo: Repository) {
    repo.cache = [] // ✓ same actor, no await needed
  }
}

// From outside — must hop in explicitly
Task.detached {
  // repo.cache = []  ← ✗ not isolated to DatabaseActor
  Task { @DatabaseActor in
    repo.cache = [] // ✓
  }
}</xmp>
				</code>
			</pre>
		</div>
						</div>
				</div>
					</div>
		</div>
					</div>
		</section>
				<section class="elementor-section elementor-top-section elementor-element elementor-element-7651440 elementor-section-boxed elementor-section-height-default elementor-section-height-default" data-id="7651440" data-element_type="section" data-e-type="section">
						<div class="elementor-container elementor-column-gap-default">
					<div class="elementor-column elementor-col-100 elementor-top-column elementor-element elementor-element-c6d2833" data-id="c6d2833" data-element_type="column" data-e-type="column">
			<div class="elementor-widget-wrap">
							</div>
		</div>
					</div>
		</section>
				</div>
		]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>Observe interface orientation in SwiftUI</title>
		<link>https://iosdeveloperdiary.com/observe-interface-orientation-in-swiftui/</link>
					<comments>https://iosdeveloperdiary.com/observe-interface-orientation-in-swiftui/#respond</comments>
		
		<dc:creator><![CDATA[Tomasz]]></dc:creator>
		<pubDate>Wed, 06 Mar 2024 13:14:31 +0000</pubDate>
				<category><![CDATA[Uncategorized]]></category>
		<category><![CDATA[interface orientation]]></category>
		<category><![CDATA[InterfaceOrientation]]></category>
		<category><![CDATA[landscape]]></category>
		<category><![CDATA[portrait]]></category>
		<category><![CDATA[SwiftUI]]></category>
		<guid isPermaLink="false">https://iosdeveloperdiary.com/?p=424</guid>

					<description><![CDATA[&#8220;Apple strongly discourages the use of &#8216;landscape&#8217; and &#8216;portrait&#8217; modes in applications and strongly encourages the use of size classes.&#8221; That being said, sometimes we really need to know whether [&#8230;]]]></description>
										<content:encoded><![CDATA[		<div data-elementor-type="wp-post" data-elementor-id="424" class="elementor elementor-424" data-elementor-post-type="post">
						<section class="elementor-section elementor-top-section elementor-element elementor-element-0edd75a elementor-section-boxed elementor-section-height-default elementor-section-height-default" data-id="0edd75a" data-element_type="section" data-e-type="section">
						<div class="elementor-container elementor-column-gap-default">
					<div class="elementor-column elementor-col-100 elementor-top-column elementor-element elementor-element-8f234dd" data-id="8f234dd" data-element_type="column" data-e-type="column">
			<div class="elementor-widget-wrap elementor-element-populated">
						<div class="elementor-element elementor-element-d25e343 elementor-widget elementor-widget-text-editor" data-id="d25e343" data-element_type="widget" data-e-type="widget" data-widget_type="text-editor.default">
				<div class="elementor-widget-container">
									<p><em><span style="caret-color: #333333; color: #333333; font-family: -apple-system, 'SF Pro Text', 'Helvetica Neue', HelveticaNeue, Helvetica, Arial, sans-serif; letter-spacing: -0.078px;">&#8220;Apple strongly discourages the use of &#8216;landscape&#8217; and &#8216;portrait&#8217; modes in applications and strongly encourages the use of size classes.&#8221;</span></em></p>								</div>
				</div>
					</div>
		</div>
					</div>
		</section>
				<section class="elementor-section elementor-top-section elementor-element elementor-element-782f801 elementor-section-boxed elementor-section-height-default elementor-section-height-default" data-id="782f801" data-element_type="section" data-e-type="section">
						<div class="elementor-container elementor-column-gap-default">
					<div class="elementor-column elementor-col-100 elementor-top-column elementor-element elementor-element-f1a8b8f" data-id="f1a8b8f" data-element_type="column" data-e-type="column">
			<div class="elementor-widget-wrap elementor-element-populated">
						<div class="elementor-element elementor-element-285252f elementor-widget elementor-widget-text-editor" data-id="285252f" data-element_type="widget" data-e-type="widget" data-widget_type="text-editor.default">
				<div class="elementor-widget-container">
									<p>That being said, sometimes we really need to know whether a device is in a landscape or portrait mode or even distinguish between landscape right and landscape left.</p><p>The most commonly used method found on the internet involves observing <span style="white-space: pre-wrap; color: #5c2699; font-family: SFMono-Regular, Menlo, Monaco, Consolas, 'Liberation Mono', 'Courier New', monospace; font-size: 13px; letter-spacing: -0.078px; background-color: #f2f2f2;">UIDevice</span><span style="white-space: pre-wrap; caret-color: #333333; color: #333333; font-family: SFMono-Regular, Menlo, Monaco, Consolas, 'Liberation Mono', 'Courier New', monospace; font-size: 13px; letter-spacing: -0.078px; background-color: #f2f2f2;">.orientationDidChangeNotification</span>. Unfortunately, this method is not entirely accurate. The device&#8217;s orientation and the interface orientation are two different things. For instance, the device orientation may include values like .faceUp or .faceDown, which do not translate to interface orientation. Additionally, even if the user enables rotation lock for the device, the device orientation may still change while the interface remains unchanged.</p>								</div>
				</div>
					</div>
		</div>
					</div>
		</section>
				<section class="elementor-section elementor-top-section elementor-element elementor-element-bf8b559 elementor-section-boxed elementor-section-height-default elementor-section-height-default" data-id="bf8b559" data-element_type="section" data-e-type="section">
						<div class="elementor-container elementor-column-gap-default">
					<div class="elementor-column elementor-col-100 elementor-top-column elementor-element elementor-element-563b305" data-id="563b305" data-element_type="column" data-e-type="column">
			<div class="elementor-widget-wrap elementor-element-populated">
						<div class="elementor-element elementor-element-1ed14d6 elementor-widget elementor-widget-text-editor" data-id="1ed14d6" data-element_type="widget" data-e-type="widget" data-widget_type="text-editor.default">
				<div class="elementor-widget-container">
									<p>Thus, how can we accurately observe the true interface orientation? Retrieve it from:<span style="font-family: var( --e-global-typography-text-font-family ), Sans-serif;"> </span><span style="color: #6c36a9; font-family: Menlo; font-size: 11px;">view</span><span style="font-family: Menlo; font-size: 11px; color: rgba(0, 0, 0, 0.85);">.</span><span style="color: #6c36a9; font-family: Menlo; font-size: 11px;">window</span><span style="font-family: Menlo; font-size: 11px; color: rgba(0, 0, 0, 0.85);">?.</span><span style="color: #6c36a9; font-family: Menlo; font-size: 11px;">windowScene</span><span style="font-family: Menlo; font-size: 11px; color: rgba(0, 0, 0, 0.85);">?.</span><span style="color: #6c36a9; font-family: Menlo; font-size: 11px;">interfaceOrientation</span></p>								</div>
				</div>
					</div>
		</div>
					</div>
		</section>
				<section class="elementor-section elementor-top-section elementor-element elementor-element-c582336 elementor-section-boxed elementor-section-height-default elementor-section-height-default" data-id="c582336" data-element_type="section" data-e-type="section">
						<div class="elementor-container elementor-column-gap-default">
					<div class="elementor-column elementor-col-100 elementor-top-column elementor-element elementor-element-977db47" data-id="977db47" data-element_type="column" data-e-type="column">
			<div class="elementor-widget-wrap elementor-element-populated">
						<div class="elementor-element elementor-element-6a45dea elementor-widget elementor-widget-text-editor" data-id="6a45dea" data-element_type="widget" data-e-type="widget" data-widget_type="text-editor.default">
				<div class="elementor-widget-container">
									<p>1. UIViewController that notifies about current interface orientation via Combine:</p>								</div>
				</div>
					</div>
		</div>
					</div>
		</section>
				<section class="elementor-section elementor-top-section elementor-element elementor-element-6180eb9 elementor-section-boxed elementor-section-height-default elementor-section-height-default" data-id="6180eb9" data-element_type="section" data-e-type="section">
						<div class="elementor-container elementor-column-gap-default">
					<div class="elementor-column elementor-col-100 elementor-top-column elementor-element elementor-element-217da68" data-id="217da68" data-element_type="column" data-e-type="column">
			<div class="elementor-widget-wrap elementor-element-populated">
						<div class="elementor-element elementor-element-ce19961 elementor-widget elementor-widget-code-highlight" data-id="ce19961" data-element_type="widget" data-e-type="widget" data-widget_type="code-highlight.default">
				<div class="elementor-widget-container">
							<div class="prismjs-default copy-to-clipboard ">
			<pre data-line="" class="highlight-height language-swift ">
				<code readonly="true" class="language-swift">
					<xmp>class InterfaceOrientationProviderVC: UIViewController {
    private let interfaceOrientationSubject: CurrentValueSubject<UIInterfaceOrientation, Never>
    
    init(interfaceOrientationSubject: CurrentValueSubject<UIInterfaceOrientation, Never>) {
        self.interfaceOrientationSubject = interfaceOrientationSubject
        super.init(nibName: nil, bundle: nil)
    }
    
    required init?(coder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }
    
    override func viewWillLayoutSubviews() {
        super.viewWillLayoutSubviews()
        
        // Set initial interfaceOrientation
        interfaceOrientationSubject.send(
            view.window?.windowScene?.interfaceOrientation ?? .unknown
        )
    }
    
    override func viewWillTransition(to size: CGSize, with coordinator: UIViewControllerTransitionCoordinator) {

        // Update interfaceOrientation
        interfaceOrientationSubject.send(
            view.window?.windowScene?.interfaceOrientation ?? .unknown
        )
    }
}</xmp>
				</code>
			</pre>
		</div>
						</div>
				</div>
					</div>
		</div>
					</div>
		</section>
				<section class="elementor-section elementor-top-section elementor-element elementor-element-ac1878c elementor-section-boxed elementor-section-height-default elementor-section-height-default" data-id="ac1878c" data-element_type="section" data-e-type="section">
						<div class="elementor-container elementor-column-gap-default">
					<div class="elementor-column elementor-col-100 elementor-top-column elementor-element elementor-element-16d9ee6" data-id="16d9ee6" data-element_type="column" data-e-type="column">
			<div class="elementor-widget-wrap elementor-element-populated">
						<div class="elementor-element elementor-element-d5bf1f5 elementor-widget elementor-widget-text-editor" data-id="d5bf1f5" data-element_type="widget" data-e-type="widget" data-widget_type="text-editor.default">
				<div class="elementor-widget-container">
									<p>2. Wrap view controller into SwiftUI view:</p>								</div>
				</div>
					</div>
		</div>
					</div>
		</section>
				<section class="elementor-section elementor-top-section elementor-element elementor-element-6342d00 elementor-section-boxed elementor-section-height-default elementor-section-height-default" data-id="6342d00" data-element_type="section" data-e-type="section">
						<div class="elementor-container elementor-column-gap-default">
					<div class="elementor-column elementor-col-100 elementor-top-column elementor-element elementor-element-34d009e" data-id="34d009e" data-element_type="column" data-e-type="column">
			<div class="elementor-widget-wrap elementor-element-populated">
						<div class="elementor-element elementor-element-bae69c4 elementor-widget elementor-widget-code-highlight" data-id="bae69c4" data-element_type="widget" data-e-type="widget" data-widget_type="code-highlight.default">
				<div class="elementor-widget-container">
							<div class="prismjs-default copy-to-clipboard ">
			<pre data-line="" class="highlight-height language-swift ">
				<code readonly="true" class="language-swift">
					<xmp>struct InterfaceOrientationProviderView: UIViewControllerRepresentable {
    let interfaceOrientationSubject: CurrentValueSubject<UIInterfaceOrientation, Never>
    
    func makeUIViewController(context: Context) -> InterfaceOrientationProviderVC {
        InterfaceOrientationProviderVC(interfaceOrientationSubject: interfaceOrientationSubject)
    }
    
    func updateUIViewController(_ uiViewController: InterfaceOrientationProviderVC, context: Context) { }
}</xmp>
				</code>
			</pre>
		</div>
						</div>
				</div>
					</div>
		</div>
					</div>
		</section>
				<section class="elementor-section elementor-top-section elementor-element elementor-element-d1d432f elementor-section-boxed elementor-section-height-default elementor-section-height-default" data-id="d1d432f" data-element_type="section" data-e-type="section">
						<div class="elementor-container elementor-column-gap-default">
					<div class="elementor-column elementor-col-100 elementor-top-column elementor-element elementor-element-bbe1d50" data-id="bbe1d50" data-element_type="column" data-e-type="column">
			<div class="elementor-widget-wrap elementor-element-populated">
						<div class="elementor-element elementor-element-bb42bd3 elementor-widget elementor-widget-text-editor" data-id="bb42bd3" data-element_type="widget" data-e-type="widget" data-widget_type="text-editor.default">
				<div class="elementor-widget-container">
									<p>3. Create ViewModifier which will observe interfaceOrientation changes and pass them to SwiftUI via environment value:</p>								</div>
				</div>
					</div>
		</div>
					</div>
		</section>
				<section class="elementor-section elementor-top-section elementor-element elementor-element-8dc9e5a elementor-section-boxed elementor-section-height-default elementor-section-height-default" data-id="8dc9e5a" data-element_type="section" data-e-type="section">
						<div class="elementor-container elementor-column-gap-default">
					<div class="elementor-column elementor-col-100 elementor-top-column elementor-element elementor-element-b84e539" data-id="b84e539" data-element_type="column" data-e-type="column">
			<div class="elementor-widget-wrap elementor-element-populated">
						<div class="elementor-element elementor-element-9be6c22 elementor-widget elementor-widget-code-highlight" data-id="9be6c22" data-element_type="widget" data-e-type="widget" data-widget_type="code-highlight.default">
				<div class="elementor-widget-container">
							<div class="prismjs-default copy-to-clipboard ">
			<pre data-line="" class="highlight-height language-swift ">
				<code readonly="true" class="language-swift">
					<xmp>private struct InterfaceOrientationKey: EnvironmentKey {
    static let defaultValue: InterfaceOrientation = .portrait
}

extension EnvironmentValues {
    var interfaceOrientation: InterfaceOrientation {
        get { self[InterfaceOrientationKey.self] }
        set { self[InterfaceOrientationKey.self] = newValue }
    }
}

private struct InterfaceOrientationViewModifier: ViewModifier {
    private let interfaceOrientationSubject: CurrentValueSubject<UIInterfaceOrientation, Never> = .init(.portrait)
    @State private var interfaceOrientation: InterfaceOrientation = .portrait

    func body(content: Content) -> some View {
        ZStack {
            InterfaceOrientationProviderView(interfaceOrientationSubject: interfaceOrientationSubject)
            
            content
                .onReceive(interfaceOrientationSubject, perform: { orientation in
                    self.interfaceOrientation = orientation.swiftUI
                })
                .environment(\.interfaceOrientation, interfaceOrientation)
        }
    }
}

extension UIInterfaceOrientation {
    /// Map from UIKit's UIInterfaceOrientation to SwiftUI's InterfaceOrientation
    var swiftUI: InterfaceOrientation {
        switch self {
        case .portrait: return .portrait
        case .landscapeLeft: return .landscapeLeft
        case .landscapeRight: return .landscapeRight
        case .portraitUpsideDown: return .portraitUpsideDown
            
        case .unknown: return .portrait
        @unknown default: return .portrait
        }
    }
}</xmp>
				</code>
			</pre>
		</div>
						</div>
				</div>
					</div>
		</div>
					</div>
		</section>
				<section class="elementor-section elementor-top-section elementor-element elementor-element-7e49233 elementor-section-boxed elementor-section-height-default elementor-section-height-default" data-id="7e49233" data-element_type="section" data-e-type="section">
						<div class="elementor-container elementor-column-gap-default">
					<div class="elementor-column elementor-col-100 elementor-top-column elementor-element elementor-element-61db49b" data-id="61db49b" data-element_type="column" data-e-type="column">
			<div class="elementor-widget-wrap elementor-element-populated">
						<div class="elementor-element elementor-element-62930df elementor-widget elementor-widget-text-editor" data-id="62930df" data-element_type="widget" data-e-type="widget" data-widget_type="text-editor.default">
				<div class="elementor-widget-container">
									<p>4. Add convenient method to apply our view modifier:</p>								</div>
				</div>
					</div>
		</div>
					</div>
		</section>
				<section class="elementor-section elementor-top-section elementor-element elementor-element-b57cd63 elementor-section-boxed elementor-section-height-default elementor-section-height-default" data-id="b57cd63" data-element_type="section" data-e-type="section">
						<div class="elementor-container elementor-column-gap-default">
					<div class="elementor-column elementor-col-100 elementor-top-column elementor-element elementor-element-b508440" data-id="b508440" data-element_type="column" data-e-type="column">
			<div class="elementor-widget-wrap elementor-element-populated">
						<div class="elementor-element elementor-element-0867e23 elementor-widget elementor-widget-code-highlight" data-id="0867e23" data-element_type="widget" data-e-type="widget" data-widget_type="code-highlight.default">
				<div class="elementor-widget-container">
							<div class="prismjs-default copy-to-clipboard ">
			<pre data-line="" class="highlight-height language-swift ">
				<code readonly="true" class="language-swift">
					<xmp>extension View {
    func observeIntefaceOrientation() -> some View {
        self.modifier(InterfaceOrientationViewModifier())
    }
}</xmp>
				</code>
			</pre>
		</div>
						</div>
				</div>
					</div>
		</div>
					</div>
		</section>
				<section class="elementor-section elementor-top-section elementor-element elementor-element-01bb24f elementor-section-boxed elementor-section-height-default elementor-section-height-default" data-id="01bb24f" data-element_type="section" data-e-type="section">
						<div class="elementor-container elementor-column-gap-default">
					<div class="elementor-column elementor-col-100 elementor-top-column elementor-element elementor-element-2a0d89a" data-id="2a0d89a" data-element_type="column" data-e-type="column">
			<div class="elementor-widget-wrap elementor-element-populated">
						<div class="elementor-element elementor-element-d11ef21 elementor-widget elementor-widget-text-editor" data-id="d11ef21" data-element_type="widget" data-e-type="widget" data-widget_type="text-editor.default">
				<div class="elementor-widget-container">
									<p>5. Apply this modifier to main application/window view</p>								</div>
				</div>
					</div>
		</div>
					</div>
		</section>
				<section class="elementor-section elementor-top-section elementor-element elementor-element-41e73ae elementor-section-boxed elementor-section-height-default elementor-section-height-default" data-id="41e73ae" data-element_type="section" data-e-type="section">
						<div class="elementor-container elementor-column-gap-default">
					<div class="elementor-column elementor-col-100 elementor-top-column elementor-element elementor-element-948c50a" data-id="948c50a" data-element_type="column" data-e-type="column">
			<div class="elementor-widget-wrap elementor-element-populated">
						<div class="elementor-element elementor-element-68510c9 elementor-widget elementor-widget-code-highlight" data-id="68510c9" data-element_type="widget" data-e-type="widget" data-widget_type="code-highlight.default">
				<div class="elementor-widget-container">
							<div class="prismjs-default copy-to-clipboard ">
			<pre data-line="" class="highlight-height language-swift ">
				<code readonly="true" class="language-swift">
					<xmp>@main
struct TestApp: App {
    var body: some Scene {
        WindowGroup {
            ContentView()
                .observeIntefaceOrientation()
        }
    }
}</xmp>
				</code>
			</pre>
		</div>
						</div>
				</div>
					</div>
		</div>
					</div>
		</section>
				<section class="elementor-section elementor-top-section elementor-element elementor-element-15aa969 elementor-section-boxed elementor-section-height-default elementor-section-height-default" data-id="15aa969" data-element_type="section" data-e-type="section">
						<div class="elementor-container elementor-column-gap-default">
					<div class="elementor-column elementor-col-100 elementor-top-column elementor-element elementor-element-e03f947" data-id="e03f947" data-element_type="column" data-e-type="column">
			<div class="elementor-widget-wrap elementor-element-populated">
						<div class="elementor-element elementor-element-84fb594 elementor-widget elementor-widget-text-editor" data-id="84fb594" data-element_type="widget" data-e-type="widget" data-widget_type="text-editor.default">
				<div class="elementor-widget-container">
									<p>And after that we can use it in our views:</p>								</div>
				</div>
					</div>
		</div>
					</div>
		</section>
				<section class="elementor-section elementor-top-section elementor-element elementor-element-96e25a0 elementor-section-boxed elementor-section-height-default elementor-section-height-default" data-id="96e25a0" data-element_type="section" data-e-type="section">
						<div class="elementor-container elementor-column-gap-default">
					<div class="elementor-column elementor-col-100 elementor-top-column elementor-element elementor-element-07b086e" data-id="07b086e" data-element_type="column" data-e-type="column">
			<div class="elementor-widget-wrap elementor-element-populated">
						<div class="elementor-element elementor-element-0a13438 elementor-widget elementor-widget-code-highlight" data-id="0a13438" data-element_type="widget" data-e-type="widget" data-widget_type="code-highlight.default">
				<div class="elementor-widget-container">
							<div class="prismjs-default copy-to-clipboard ">
			<pre data-line="" class="highlight-height language-swift ">
				<code readonly="true" class="language-swift">
					<xmp>struct SomeView: View {
    @Environment(\.interfaceOrientation) private var interfaceOrientation

    var body: some View {
        HStack {
            Text("Current interface orientation:")
            Text(interfaceOrientation.id)
        }
    }
}</xmp>
				</code>
			</pre>
		</div>
						</div>
				</div>
					</div>
		</div>
					</div>
		</section>
				</div>
		]]></content:encoded>
					
					<wfw:commentRss>https://iosdeveloperdiary.com/observe-interface-orientation-in-swiftui/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>AWS Amplify partial model update</title>
		<link>https://iosdeveloperdiary.com/aws-amplify-partial-model-update/</link>
					<comments>https://iosdeveloperdiary.com/aws-amplify-partial-model-update/#respond</comments>
		
		<dc:creator><![CDATA[Tomasz]]></dc:creator>
		<pubDate>Sat, 27 Jan 2024 18:08:37 +0000</pubDate>
				<category><![CDATA[Uncategorized]]></category>
		<category><![CDATA[amplify]]></category>
		<category><![CDATA[AWS]]></category>
		<category><![CDATA[partial edit]]></category>
		<category><![CDATA[single field edit]]></category>
		<guid isPermaLink="false">https://iosdeveloperdiary.com/?p=360</guid>

					<description><![CDATA[Amplify does not allow for the modification of just one field in the model, we always have to send all of its data. This becomes a significant issue when more [&#8230;]]]></description>
										<content:encoded><![CDATA[		<div data-elementor-type="wp-post" data-elementor-id="360" class="elementor elementor-360" data-elementor-post-type="post">
						<section class="elementor-section elementor-top-section elementor-element elementor-element-8c44c06 elementor-section-boxed elementor-section-height-default elementor-section-height-default" data-id="8c44c06" data-element_type="section" data-e-type="section">
						<div class="elementor-container elementor-column-gap-default">
					<div class="elementor-column elementor-col-100 elementor-top-column elementor-element elementor-element-665fe87" data-id="665fe87" data-element_type="column" data-e-type="column">
			<div class="elementor-widget-wrap elementor-element-populated">
						<div class="elementor-element elementor-element-f5c7122 elementor-widget elementor-widget-text-editor" data-id="f5c7122" data-element_type="widget" data-e-type="widget" data-widget_type="text-editor.default">
				<div class="elementor-widget-container">
									<p><span style="white-space: pre-wrap; caret-color: #374151; color: #374151; font-family: Söhne, ui-sans-serif, system-ui, -apple-system, 'Segoe UI', Roboto, Ubuntu, Cantarell, 'Noto Sans', sans-serif, 'Helvetica Neue', Arial, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol', 'Noto Color Emoji';">Amplify does not allow for the modification of just one field in the model, we always have to send all of its data. This becomes a significant issue when more than one user is editing the same model, resulting in data being overwritten by each other.</span></p>								</div>
				</div>
					</div>
		</div>
					</div>
		</section>
				<section class="elementor-section elementor-top-section elementor-element elementor-element-83510db elementor-section-boxed elementor-section-height-default elementor-section-height-default" data-id="83510db" data-element_type="section" data-e-type="section">
						<div class="elementor-container elementor-column-gap-default">
					<div class="elementor-column elementor-col-100 elementor-top-column elementor-element elementor-element-d23d25c" data-id="d23d25c" data-element_type="column" data-e-type="column">
			<div class="elementor-widget-wrap elementor-element-populated">
						<div class="elementor-element elementor-element-4a3eb89 elementor-widget elementor-widget-text-editor" data-id="4a3eb89" data-element_type="widget" data-e-type="widget" data-widget_type="text-editor.default">
				<div class="elementor-widget-container">
									<p style="white-space: pre-wrap; border: 0px solid #d9d9e3; margin-bottom: 1.25em; caret-color: #374151; color: #374151; font-family: Söhne, ui-sans-serif, system-ui, -apple-system, 'Segoe UI', Roboto, Ubuntu, Cantarell, 'Noto Sans', sans-serif, 'Helvetica Neue', Arial, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol', 'Noto Color Emoji';">Fortunately, GraphQL requests provide such capability, and Amplify offers us many tools for constructing and sending these requests.</p><p style="white-space: pre-wrap; border: 0px solid #d9d9e3; margin-top: 1.25em; caret-color: #374151; color: #374151; font-family: Söhne, ui-sans-serif, system-ui, -apple-system, 'Segoe UI', Roboto, Ubuntu, Cantarell, 'Noto Sans', sans-serif, 'Helvetica Neue', Arial, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol', 'Noto Color Emoji';">Let&#8217;s consider such a model:</p>								</div>
				</div>
					</div>
		</div>
					</div>
		</section>
				<section class="elementor-section elementor-top-section elementor-element elementor-element-11c91c0 elementor-section-boxed elementor-section-height-default elementor-section-height-default" data-id="11c91c0" data-element_type="section" data-e-type="section">
						<div class="elementor-container elementor-column-gap-default">
					<div class="elementor-column elementor-col-100 elementor-top-column elementor-element elementor-element-74a52b7" data-id="74a52b7" data-element_type="column" data-e-type="column">
			<div class="elementor-widget-wrap elementor-element-populated">
						<div class="elementor-element elementor-element-62ca63e elementor-widget elementor-widget-code-highlight" data-id="62ca63e" data-element_type="widget" data-e-type="widget" data-widget_type="code-highlight.default">
				<div class="elementor-widget-container">
							<div class="prismjs-default copy-to-clipboard ">
			<pre data-line="" class="highlight-height language-swift ">
				<code readonly="true" class="language-swift">
					<xmp>public struct Item: Model {
  public let id: String
  public var name: String
  public var modelFile: File?
  public var imageFile: File?
}

let myItem = Item(...)</xmp>
				</code>
			</pre>
		</div>
						</div>
				</div>
					</div>
		</div>
					</div>
		</section>
				<section class="elementor-section elementor-top-section elementor-element elementor-element-74750a7 elementor-section-boxed elementor-section-height-default elementor-section-height-default" data-id="74750a7" data-element_type="section" data-e-type="section">
						<div class="elementor-container elementor-column-gap-default">
					<div class="elementor-column elementor-col-100 elementor-top-column elementor-element elementor-element-d0b586e" data-id="d0b586e" data-element_type="column" data-e-type="column">
			<div class="elementor-widget-wrap elementor-element-populated">
						<div class="elementor-element elementor-element-05aaf2b elementor-widget elementor-widget-text-editor" data-id="05aaf2b" data-element_type="widget" data-e-type="widget" data-widget_type="text-editor.default">
				<div class="elementor-widget-container">
									<p>The first thing we need to do is create a mutation GraphQL request:</p>								</div>
				</div>
					</div>
		</div>
					</div>
		</section>
				<section class="elementor-section elementor-top-section elementor-element elementor-element-268667e elementor-section-boxed elementor-section-height-default elementor-section-height-default" data-id="268667e" data-element_type="section" data-e-type="section">
						<div class="elementor-container elementor-column-gap-default">
					<div class="elementor-column elementor-col-100 elementor-top-column elementor-element elementor-element-55585f9" data-id="55585f9" data-element_type="column" data-e-type="column">
			<div class="elementor-widget-wrap elementor-element-populated">
						<div class="elementor-element elementor-element-83556d8 elementor-widget elementor-widget-code-highlight" data-id="83556d8" data-element_type="widget" data-e-type="widget" data-widget_type="code-highlight.default">
				<div class="elementor-widget-container">
							<div class="prismjs-default copy-to-clipboard ">
			<pre data-line="" class="highlight-height language-swift ">
				<code readonly="true" class="language-swift">
					<xmp>let request = GraphQLRequest<Item>.updateMutation(of: myItem)</xmp>
				</code>
			</pre>
		</div>
						</div>
				</div>
					</div>
		</div>
					</div>
		</section>
				<section class="elementor-section elementor-top-section elementor-element elementor-element-335b10a elementor-section-boxed elementor-section-height-default elementor-section-height-default" data-id="335b10a" data-element_type="section" data-e-type="section">
						<div class="elementor-container elementor-column-gap-default">
					<div class="elementor-column elementor-col-100 elementor-top-column elementor-element elementor-element-f71c508" data-id="f71c508" data-element_type="column" data-e-type="column">
			<div class="elementor-widget-wrap elementor-element-populated">
						<div class="elementor-element elementor-element-ba9c742 elementor-widget elementor-widget-text-editor" data-id="ba9c742" data-element_type="widget" data-e-type="widget" data-widget_type="text-editor.default">
				<div class="elementor-widget-container">
									<p>If we were to send the request in this form, our model would be completely modified in the database. Therefore, we need to remove all fields from the request that we don&#8217;t want to edit, which are located in the dictionary&nbsp;<span style="color: rgba(0, 0, 0, 0.85); font-family: Menlo; font-size: 11px;">request.</span><span style="font-family: Menlo; font-size: 11px; color: #326d74;">variables</span><span style="color: rgba(0, 0, 0, 0.85); font-family: Menlo; font-size: 11px;">?[</span><span style="font-family: Menlo; font-size: 11px; color: #c41a16;">&#8220;input”</span><span style="color: rgba(0, 0, 0, 0.85); font-family: Menlo; font-size: 11px;">]</span><span style="font-family: var( --e-global-typography-text-font-family ), Sans-serif;">&nbsp;&#8211; we just need to remove them.</span></p>
<p><span style="white-space: pre-wrap; caret-color: #374151; color: #374151; font-family: Söhne, ui-sans-serif, system-ui, -apple-system, 'Segoe UI', Roboto, Ubuntu, Cantarell, 'Noto Sans', sans-serif, 'Helvetica Neue', Arial, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol', 'Noto Color Emoji';">Unfortunately, the fields in the GraphQLRequest structure are <i>constant let</i>, so we need to copy them, edit, and then create our own request instance by referencing everything from the previously generated one:</span><span style="font-family: var( --e-global-typography-text-font-family ), Sans-serif;"><br></span></p>								</div>
				</div>
					</div>
		</div>
					</div>
		</section>
				<section class="elementor-section elementor-top-section elementor-element elementor-element-d302f84 elementor-section-boxed elementor-section-height-default elementor-section-height-default" data-id="d302f84" data-element_type="section" data-e-type="section">
						<div class="elementor-container elementor-column-gap-default">
					<div class="elementor-column elementor-col-100 elementor-top-column elementor-element elementor-element-0e17258" data-id="0e17258" data-element_type="column" data-e-type="column">
			<div class="elementor-widget-wrap elementor-element-populated">
						<div class="elementor-element elementor-element-8247d8e elementor-widget elementor-widget-code-highlight" data-id="8247d8e" data-element_type="widget" data-e-type="widget" data-widget_type="code-highlight.default">
				<div class="elementor-widget-container">
							<div class="prismjs-default copy-to-clipboard word-wrap">
			<pre data-line="" class="highlight-height language-swift ">
				<code readonly="true" class="language-swift">
					<xmp>var input = (request.variables?["input"] as? [String: Any]) ?? [:]

// Do not modify modelFile field
input.removeValue(forKey: Item.CodingKeys.modelFile.stringValue)

let editedRequest = GraphQLRequest<MutationSyncResult>(apiName: request.apiName, document: request.document, variables: ["input": input], responseType: request.responseType, decodePath: request.decodePath, options: request.options)</xmp>
				</code>
			</pre>
		</div>
						</div>
				</div>
					</div>
		</div>
					</div>
		</section>
				<section class="elementor-section elementor-top-section elementor-element elementor-element-173df1b elementor-section-boxed elementor-section-height-default elementor-section-height-default" data-id="173df1b" data-element_type="section" data-e-type="section">
						<div class="elementor-container elementor-column-gap-default">
					<div class="elementor-column elementor-col-100 elementor-top-column elementor-element elementor-element-a6ac3fb" data-id="a6ac3fb" data-element_type="column" data-e-type="column">
			<div class="elementor-widget-wrap elementor-element-populated">
						<div class="elementor-element elementor-element-364a657 elementor-widget elementor-widget-text-editor" data-id="364a657" data-element_type="widget" data-e-type="widget" data-widget_type="text-editor.default">
				<div class="elementor-widget-container">
									<p><span style="white-space: pre-wrap; caret-color: #374151; color: #374151; font-family: Söhne, ui-sans-serif, system-ui, -apple-system, 'Segoe UI', Roboto, Ubuntu, Cantarell, 'Noto Sans', sans-serif, 'Helvetica Neue', Arial, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol', 'Noto Color Emoji';">And then we simply need to send it:</span></p>								</div>
				</div>
					</div>
		</div>
					</div>
		</section>
				<section class="elementor-section elementor-top-section elementor-element elementor-element-5f25f9f elementor-section-boxed elementor-section-height-default elementor-section-height-default" data-id="5f25f9f" data-element_type="section" data-e-type="section">
						<div class="elementor-container elementor-column-gap-default">
					<div class="elementor-column elementor-col-100 elementor-top-column elementor-element elementor-element-bac507e" data-id="bac507e" data-element_type="column" data-e-type="column">
			<div class="elementor-widget-wrap elementor-element-populated">
						<div class="elementor-element elementor-element-2dd06a8 elementor-widget elementor-widget-code-highlight" data-id="2dd06a8" data-element_type="widget" data-e-type="widget" data-widget_type="code-highlight.default">
				<div class="elementor-widget-container">
							<div class="prismjs-default copy-to-clipboard ">
			<pre data-line="" class="highlight-height language-swift ">
				<code readonly="true" class="language-swift">
					<xmp>let result = try await Amplify.API.mutate(request: editedRequest)
let updatedItem = try result.get().model.instance as? Item</xmp>
				</code>
			</pre>
		</div>
						</div>
				</div>
					</div>
		</div>
					</div>
		</section>
				<section class="elementor-section elementor-top-section elementor-element elementor-element-f5d5beb elementor-section-boxed elementor-section-height-default elementor-section-height-default" data-id="f5d5beb" data-element_type="section" data-e-type="section">
						<div class="elementor-container elementor-column-gap-default">
					<div class="elementor-column elementor-col-100 elementor-top-column elementor-element elementor-element-02dfeb2" data-id="02dfeb2" data-element_type="column" data-e-type="column">
			<div class="elementor-widget-wrap elementor-element-populated">
						<div class="elementor-element elementor-element-ff60536 elementor-widget elementor-widget-text-editor" data-id="ff60536" data-element_type="widget" data-e-type="widget" data-widget_type="text-editor.default">
				<div class="elementor-widget-container">
									<p>Summarizing everything up to this point, the method for editing the Item model could look like this:</p>								</div>
				</div>
					</div>
		</div>
					</div>
		</section>
				<section class="elementor-section elementor-top-section elementor-element elementor-element-0e9146b elementor-section-boxed elementor-section-height-default elementor-section-height-default" data-id="0e9146b" data-element_type="section" data-e-type="section">
						<div class="elementor-container elementor-column-gap-default">
					<div class="elementor-column elementor-col-100 elementor-top-column elementor-element elementor-element-41b76d7" data-id="41b76d7" data-element_type="column" data-e-type="column">
			<div class="elementor-widget-wrap elementor-element-populated">
						<div class="elementor-element elementor-element-b5e8478 elementor-widget elementor-widget-code-highlight" data-id="b5e8478" data-element_type="widget" data-e-type="widget" data-widget_type="code-highlight.default">
				<div class="elementor-widget-container">
							<div class="prismjs-default copy-to-clipboard ">
			<pre data-line="" class="highlight-height language-swift ">
				<code readonly="true" class="language-swift">
					<xmp>    private static func updateItem(item: Item, updates: [Item.CodingKeys : Encodable]) async throws -> Item {
        let tmpRequest = GraphQLRequest<Item>.updateMutation(of: item)
        
        var input = (tmpRequest.variables?["input"] as? [String: Any]) ?? [:]
        for key in Item.CodingKeys.allCases {
            
            // Do not remove id from input
            if key.stringValue == AnyModel.CodingKeys.id.stringValue { continue }
            
            if let newValue = updates[key] {
                
                // UPDATE this value
                do {
                    let newValueData = try JSONEncoder().encode(newValue)
                    let newValueJson = try JSONSerialization.jsonObject(with: newValueData)
                    input[key.stringValue] = newValueJson
                    
                } catch {
                    input[key.stringValue] = newValue
                }
                
            } else {
                // DO NOT UPDATE this value
                input.removeValue(forKey: key.stringValue)
            }
        }
        
        let request = GraphQLRequest<MutationSyncResult>(apiName: tmpRequest.apiName, document: tmpRequest.document, variables: ["input": input], responseType: tmpRequest.responseType, decodePath: tmpRequest.decodePath, options: tmpRequest.options)
        let result = try await Amplify.API.mutate(request: request)
        
        guard let newModel = try result.get().model.instance as? Item else {
            throw nilResultError
        }
        
        return newModel
    }</xmp>
				</code>
			</pre>
		</div>
						</div>
				</div>
					</div>
		</div>
					</div>
		</section>
				<section class="elementor-section elementor-top-section elementor-element elementor-element-fa95f4d elementor-section-boxed elementor-section-height-default elementor-section-height-default" data-id="fa95f4d" data-element_type="section" data-e-type="section">
						<div class="elementor-container elementor-column-gap-default">
					<div class="elementor-column elementor-col-100 elementor-top-column elementor-element elementor-element-8969837" data-id="8969837" data-element_type="column" data-e-type="column">
			<div class="elementor-widget-wrap elementor-element-populated">
						<div class="elementor-element elementor-element-23f58d6 elementor-widget elementor-widget-text-editor" data-id="23f58d6" data-element_type="widget" data-e-type="widget" data-widget_type="text-editor.default">
				<div class="elementor-widget-container">
									<p><span style="white-space: pre-wrap; caret-color: #374151; color: #374151; font-family: Söhne, ui-sans-serif, system-ui, -apple-system, 'Segoe UI', Roboto, Ubuntu, Cantarell, 'Noto Sans', sans-serif, 'Helvetica Neue', Arial, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol', 'Noto Color Emoji';">Looks fine, but could it be done more generic? So that we don&#8217;t have to write the same code for each model?</span></p><p><span style="caret-color: #374151; color: #374151; font-family: Söhne, ui-sans-serif, system-ui, -apple-system, 'Segoe UI', Roboto, Ubuntu, Cantarell, 'Noto Sans', sans-serif, 'Helvetica Neue', Arial, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol', 'Noto Color Emoji'; white-space: pre-wrap;">Yes! Just mark every model we want to modify as conforming to &#8216;HasCodingKeys&#8217; protocol and and change our function accordingly:</span></p>								</div>
				</div>
					</div>
		</div>
					</div>
		</section>
				<section class="elementor-section elementor-top-section elementor-element elementor-element-37e9ce6 elementor-section-boxed elementor-section-height-default elementor-section-height-default" data-id="37e9ce6" data-element_type="section" data-e-type="section">
						<div class="elementor-container elementor-column-gap-default">
					<div class="elementor-column elementor-col-100 elementor-top-column elementor-element elementor-element-e10dfe1" data-id="e10dfe1" data-element_type="column" data-e-type="column">
			<div class="elementor-widget-wrap elementor-element-populated">
						<div class="elementor-element elementor-element-d953a08 elementor-widget elementor-widget-code-highlight" data-id="d953a08" data-element_type="widget" data-e-type="widget" data-widget_type="code-highlight.default">
				<div class="elementor-widget-container">
							<div class="prismjs-default copy-to-clipboard ">
			<pre data-line="" class="highlight-height language-swift ">
				<code readonly="true" class="language-swift">
					<xmp>protocol HasCodindKeys: Model {
    associatedtype Keys: ModelKey
    static var keys: Keys.Type { get }
}

// Item model conforms to HasCodingKeys protocol
extension Item: HasCodindKeys {}

// Our final implementation:
private static func updateModel<T: HasCodindKeys>(model: T, updates: [T.Keys: Encodable]) async throws -> T {

        let tmpRequest = GraphQLRequest<T>.updateMutation(of: model)

        var input = (tmpRequest.variables?["input"] as? [String: Any]) ?? [:]
        for key in T.Keys.allCases {
            
            // Do not remove id from input
            if key.stringValue == AnyModel.CodingKeys.id.stringValue { continue }

            if let newValue = updates[key] {
                
                // UPDATE this value
                do {
                    let newValueData = try JSONEncoder().encode(newValue)
                    let newValueJson = try JSONSerialization.jsonObject(with: newValueData)
                    input[key.stringValue] = newValueJson
                    
                } catch {
                    input[key.stringValue] = newValue
                }
                
            } else {
                // DO NOT UPDATE this value
                input.removeValue(forKey: key.stringValue)
            }
        }

        let request = GraphQLRequest<MutationSyncResult>(apiName: tmpRequest.apiName, document: tmpRequest.document, variables: ["input": input], responseType: tmpRequest.responseType, decodePath: tmpRequest.decodePath, options: tmpRequest.options)
        let result = try await Amplify.API.mutate(request: request)

        guard let newModel = try result.get().model.instance as? T else {
            throw nilResultError
        }

        return newModel
    }</xmp>
				</code>
			</pre>
		</div>
						</div>
				</div>
					</div>
		</div>
					</div>
		</section>
				<section class="elementor-section elementor-top-section elementor-element elementor-element-aa36a42 elementor-section-boxed elementor-section-height-default elementor-section-height-default" data-id="aa36a42" data-element_type="section" data-e-type="section">
						<div class="elementor-container elementor-column-gap-default">
					<div class="elementor-column elementor-col-100 elementor-top-column elementor-element elementor-element-d38565f" data-id="d38565f" data-element_type="column" data-e-type="column">
			<div class="elementor-widget-wrap elementor-element-populated">
						<div class="elementor-element elementor-element-dc1d7ad elementor-widget elementor-widget-text-editor" data-id="dc1d7ad" data-element_type="widget" data-e-type="widget" data-widget_type="text-editor.default">
				<div class="elementor-widget-container">
									<p>Example updating item&#8217;s <i>name</i> and <i>imageFile</i> without changing <i>modelFile</i>:</p>								</div>
				</div>
					</div>
		</div>
					</div>
		</section>
				<section class="elementor-section elementor-top-section elementor-element elementor-element-3f5bf0f elementor-section-boxed elementor-section-height-default elementor-section-height-default" data-id="3f5bf0f" data-element_type="section" data-e-type="section">
						<div class="elementor-container elementor-column-gap-default">
					<div class="elementor-column elementor-col-100 elementor-top-column elementor-element elementor-element-f3fbec0" data-id="f3fbec0" data-element_type="column" data-e-type="column">
			<div class="elementor-widget-wrap elementor-element-populated">
						<div class="elementor-element elementor-element-2f3a943 elementor-widget elementor-widget-code-highlight" data-id="2f3a943" data-element_type="widget" data-e-type="widget" data-widget_type="code-highlight.default">
				<div class="elementor-widget-container">
							<div class="prismjs-default copy-to-clipboard ">
			<pre data-line="" class="highlight-height language-swift ">
				<code readonly="true" class="language-swift">
					<xmp>        try await updateItem(item: myItem, updates: [
                .name: "New item name",
                .imageFile: File(url: url)
            ]
        )</xmp>
				</code>
			</pre>
		</div>
						</div>
				</div>
					</div>
		</div>
					</div>
		</section>
				<section class="elementor-section elementor-top-section elementor-element elementor-element-8ae8d11 elementor-section-boxed elementor-section-height-default elementor-section-height-default" data-id="8ae8d11" data-element_type="section" data-e-type="section">
						<div class="elementor-container elementor-column-gap-default">
					<div class="elementor-column elementor-col-100 elementor-top-column elementor-element elementor-element-5be5420" data-id="5be5420" data-element_type="column" data-e-type="column">
			<div class="elementor-widget-wrap elementor-element-populated">
						<div class="elementor-element elementor-element-fe308cf elementor-widget elementor-widget-text-editor" data-id="fe308cf" data-element_type="widget" data-e-type="widget" data-widget_type="text-editor.default">
				<div class="elementor-widget-container">
									<p><span style="white-space: pre-wrap; caret-color: #374151; color: #374151; font-family: Söhne, ui-sans-serif, system-ui, -apple-system, 'Segoe UI', Roboto, Ubuntu, Cantarell, 'Noto Sans', sans-serif, 'Helvetica Neue', Arial, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol', 'Noto Color Emoji';">Warning: If you have &#8216;Conflict resolution&#8217; enabled, you need to provide the current version of the model </span><span style="caret-color: rgb(55, 65, 81); color: rgb(55, 65, 81); font-family: Söhne, ui-sans-serif, system-ui, -apple-system, &quot;Segoe UI&quot;, Roboto, Ubuntu, Cantarell, &quot;Noto Sans&quot;, sans-serif, &quot;Helvetica Neue&quot;, Arial, &quot;Apple Color Emoji&quot;, &quot;Segoe UI Emoji&quot;, &quot;Segoe UI Symbol&quot;, &quot;Noto Color Emoji&quot;; white-space: pre-wrap;">when creating a request</span><span style="white-space: pre-wrap; caret-color: #374151; color: #374151; font-family: Söhne, ui-sans-serif, system-ui, -apple-system, 'Segoe UI', Roboto, Ubuntu, Cantarell, 'Noto Sans', sans-serif, 'Helvetica Neue', Arial, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol', 'Noto Color Emoji';">:</span></p>								</div>
				</div>
					</div>
		</div>
					</div>
		</section>
				<section class="elementor-section elementor-top-section elementor-element elementor-element-8f40122 elementor-section-boxed elementor-section-height-default elementor-section-height-default" data-id="8f40122" data-element_type="section" data-e-type="section">
						<div class="elementor-container elementor-column-gap-default">
					<div class="elementor-column elementor-col-100 elementor-top-column elementor-element elementor-element-03b7b30" data-id="03b7b30" data-element_type="column" data-e-type="column">
			<div class="elementor-widget-wrap elementor-element-populated">
						<div class="elementor-element elementor-element-fd3b6d2 elementor-widget elementor-widget-code-highlight" data-id="fd3b6d2" data-element_type="widget" data-e-type="widget" data-widget_type="code-highlight.default">
				<div class="elementor-widget-container">
							<div class="prismjs-default copy-to-clipboard ">
			<pre data-line="" class="highlight-height language-swift ">
				<code readonly="true" class="language-swift">
					<xmp>let version = try await GraphQL.getModelVersion(model: myItem)
let request = GraphQLRequest<Item>.updateMutation(of: myItem, version: version)
</xmp>
				</code>
			</pre>
		</div>
						</div>
				</div>
					</div>
		</div>
					</div>
		</section>
				<section class="elementor-section elementor-top-section elementor-element elementor-element-241c8da elementor-section-boxed elementor-section-height-default elementor-section-height-default" data-id="241c8da" data-element_type="section" data-e-type="section">
						<div class="elementor-container elementor-column-gap-default">
					<div class="elementor-column elementor-col-100 elementor-top-column elementor-element elementor-element-c2e66cd" data-id="c2e66cd" data-element_type="column" data-e-type="column">
			<div class="elementor-widget-wrap elementor-element-populated">
						<div class="elementor-element elementor-element-2ced856 elementor-widget elementor-widget-text-editor" data-id="2ced856" data-element_type="widget" data-e-type="widget" data-widget_type="text-editor.default">
				<div class="elementor-widget-container">
									<p><span style="white-space: pre-wrap; caret-color: #374151; color: #374151; font-family: Söhne, ui-sans-serif, system-ui, -apple-system, 'Segoe UI', Roboto, Ubuntu, Cantarell, 'Noto Sans', sans-serif, 'Helvetica Neue', Arial, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol', 'Noto Color Emoji';">Where the <i>GraphQL.getModelVersion</i> method looks like this:</span></p>								</div>
				</div>
					</div>
		</div>
					</div>
		</section>
				<section class="elementor-section elementor-top-section elementor-element elementor-element-e8d18ae elementor-section-boxed elementor-section-height-default elementor-section-height-default" data-id="e8d18ae" data-element_type="section" data-e-type="section">
						<div class="elementor-container elementor-column-gap-default">
					<div class="elementor-column elementor-col-100 elementor-top-column elementor-element elementor-element-0a03ccd" data-id="0a03ccd" data-element_type="column" data-e-type="column">
			<div class="elementor-widget-wrap elementor-element-populated">
						<div class="elementor-element elementor-element-8637540 elementor-widget elementor-widget-code-highlight" data-id="8637540" data-element_type="widget" data-e-type="widget" data-widget_type="code-highlight.default">
				<div class="elementor-widget-container">
							<div class="prismjs-default copy-to-clipboard ">
			<pre data-line="" class="highlight-height language-swift ">
				<code readonly="true" class="language-swift">
					<xmp>    private static func getModelVersion<T: Model>(model: T) async throws -> Int {
        let request = GraphQLRequest<T>.query(modelName: model.modelName, byId: model.identifier)
        let result = try await Amplify.API.query(request: request).get()
       
        guard let version = result?.syncMetadata.version else {
            throw nilResultError
        }
        
        return version
    }
</xmp>
				</code>
			</pre>
		</div>
						</div>
				</div>
					</div>
		</div>
					</div>
		</section>
				</div>
		]]></content:encoded>
					
					<wfw:commentRss>https://iosdeveloperdiary.com/aws-amplify-partial-model-update/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>Entering async/await Task from synchronous code in serial manner</title>
		<link>https://iosdeveloperdiary.com/entering-async-await-task-from-synchronous-code-in-serial-manner/</link>
					<comments>https://iosdeveloperdiary.com/entering-async-await-task-from-synchronous-code-in-serial-manner/#respond</comments>
		
		<dc:creator><![CDATA[Tomasz]]></dc:creator>
		<pubDate>Sat, 19 Aug 2023 18:21:32 +0000</pubDate>
				<category><![CDATA[Uncategorized]]></category>
		<category><![CDATA[async/await]]></category>
		<category><![CDATA[in queue]]></category>
		<category><![CDATA[serial execution]]></category>
		<category><![CDATA[Swift]]></category>
		<guid isPermaLink="false">https://iosdeveloperdiary.com/?p=337</guid>

					<description><![CDATA[Imagine you have some code outside of a Swift Concurrency (async/await) producing values that you need to consume inside an async/await Task in the same order that they are created. [&#8230;]]]></description>
										<content:encoded><![CDATA[		<div data-elementor-type="wp-post" data-elementor-id="337" class="elementor elementor-337" data-elementor-post-type="post">
						<section class="elementor-section elementor-top-section elementor-element elementor-element-6dd469e elementor-section-boxed elementor-section-height-default elementor-section-height-default" data-id="6dd469e" data-element_type="section" data-e-type="section">
						<div class="elementor-container elementor-column-gap-default">
					<div class="elementor-column elementor-col-100 elementor-top-column elementor-element elementor-element-f3ca28e" data-id="f3ca28e" data-element_type="column" data-e-type="column">
			<div class="elementor-widget-wrap elementor-element-populated">
						<div class="elementor-element elementor-element-b8ebf7a elementor-widget elementor-widget-text-editor" data-id="b8ebf7a" data-element_type="widget" data-e-type="widget" data-widget_type="text-editor.default">
				<div class="elementor-widget-container">
									<p>Imagine you have some code outside of a Swift Concurrency (async/await) producing values that you need to consume inside an async/await Task in the same order that they are created.</p><p>Let&#8217;s see a simple example where we pass integers in a loop from a synchronous function to an async function:</p>								</div>
				</div>
					</div>
		</div>
					</div>
		</section>
				<section class="elementor-section elementor-top-section elementor-element elementor-element-97038bc elementor-section-boxed elementor-section-height-default elementor-section-height-default" data-id="97038bc" data-element_type="section" data-e-type="section">
						<div class="elementor-container elementor-column-gap-default">
					<div class="elementor-column elementor-col-100 elementor-top-column elementor-element elementor-element-d338b21" data-id="d338b21" data-element_type="column" data-e-type="column">
			<div class="elementor-widget-wrap elementor-element-populated">
						<div class="elementor-element elementor-element-1e00d49 elementor-widget elementor-widget-code-highlight" data-id="1e00d49" data-element_type="widget" data-e-type="widget" data-widget_type="code-highlight.default">
				<div class="elementor-widget-container">
							<div class="prismjs-default copy-to-clipboard ">
			<pre data-line="" class="highlight-height language-swift line-numbers">
				<code readonly="true" class="language-swift">
					<xmp>  func sendValues() {
        for i in 0..<1000 {
            Task {
                await consume(i)
            }
        }
    }
    
    func consume(_ value: Int) async {
        print(value) // values received NOT in order
    }

    /*
    Output:
    1
    4
    0
    8
    10
    9
    3
    12
    13
    14
    8
    ...
    */
    </xmp>
				</code>
			</pre>
		</div>
						</div>
				</div>
					</div>
		</div>
					</div>
		</section>
				<section class="elementor-section elementor-top-section elementor-element elementor-element-da98a4e elementor-section-boxed elementor-section-height-default elementor-section-height-default" data-id="da98a4e" data-element_type="section" data-e-type="section">
						<div class="elementor-container elementor-column-gap-default">
					<div class="elementor-column elementor-col-100 elementor-top-column elementor-element elementor-element-cb5c169" data-id="cb5c169" data-element_type="column" data-e-type="column">
			<div class="elementor-widget-wrap elementor-element-populated">
						<div class="elementor-element elementor-element-1964c12 elementor-widget elementor-widget-heading" data-id="1964c12" data-element_type="widget" data-e-type="widget" data-widget_type="heading.default">
				<div class="elementor-widget-container">
					<h2 class="elementor-heading-title elementor-size-default"><p style="font-size: 16px;font-weight: 400;white-space: normal">You&nbsp;would&nbsp;expect&nbsp;to&nbsp;see&nbsp;values&nbsp;printed&nbsp;in&nbsp;order:&nbsp;1…&nbsp;2…&nbsp;3…&nbsp;etc., but&nbsp;it&nbsp;is&nbsp;not&nbsp;the&nbsp;case&nbsp;here.<span style="font-family: var( --e-global-typography-primary-font-family ), Sans-serif;font-size: 34px;white-space: pre-wrap"></span></p></h2>				</div>
				</div>
					</div>
		</div>
					</div>
		</section>
				<section class="elementor-section elementor-top-section elementor-element elementor-element-cf4ee3b elementor-section-boxed elementor-section-height-default elementor-section-height-default" data-id="cf4ee3b" data-element_type="section" data-e-type="section">
						<div class="elementor-container elementor-column-gap-default">
					<div class="elementor-column elementor-col-100 elementor-top-column elementor-element elementor-element-2a61a94" data-id="2a61a94" data-element_type="column" data-e-type="column">
			<div class="elementor-widget-wrap elementor-element-populated">
						<div class="elementor-element elementor-element-4511afe elementor-widget__width-initial elementor-widget elementor-widget-text-editor" data-id="4511afe" data-element_type="widget" data-e-type="widget" data-widget_type="text-editor.default">
				<div class="elementor-widget-container">
									<h2 style="color: #6ec1e4; font-family: var( --e-global-typography-primary-font-family ), Sans-serif; outline-color: currentcolor; outline-style: none;" data-elementor-setting-key="title" data-pen-placeholder="Pisz tutaj..."><span style="caret-color: rgb(0, 0, 0); color: rgb(0, 0, 0); font-size: medium; font-family: var( --e-global-typography-text-font-family ), Sans-serif;"><b>The sentence above is no longer true in the official Swift 6 implementation, thanks to:</b></span><span style="color: #7a7a7a; font-size: medium;"><span style="white-space-collapse: collapse;">&nbsp;<a href="https://github.com/swiftlang/swift-evolution/blob/main/proposals/0431-isolated-any-functions.md" target="_blank" rel="noopener">SE-0431</a></span></span></h2>								</div>
				</div>
					</div>
		</div>
					</div>
		</section>
				<section class="elementor-section elementor-top-section elementor-element elementor-element-b981336 elementor-section-boxed elementor-section-height-default elementor-section-height-default" data-id="b981336" data-element_type="section" data-e-type="section">
						<div class="elementor-container elementor-column-gap-default">
					<div class="elementor-column elementor-col-100 elementor-top-column elementor-element elementor-element-7bb9f20" data-id="7bb9f20" data-element_type="column" data-e-type="column">
			<div class="elementor-widget-wrap elementor-element-populated">
						<div class="elementor-element elementor-element-ad2bf83 elementor-widget elementor-widget-text-editor" data-id="ad2bf83" data-element_type="widget" data-e-type="widget" data-widget_type="text-editor.default">
				<div class="elementor-widget-container">
									<p><span style="font-family: var( --e-global-typography-text-font-family ), Sans-serif;">Unstructured tasks created inside the loop are scheduled on the global </span><strong style="font-family: var( --e-global-typography-text-font-family ), Sans-serif;">concurrent executor</strong><span style="font-family: var( --e-global-typography-text-font-family ), Sans-serif;">, which means they can be executed in any order:</span></p>								</div>
				</div>
					</div>
		</div>
					</div>
		</section>
				<section class="elementor-section elementor-top-section elementor-element elementor-element-946b83d elementor-section-boxed elementor-section-height-default elementor-section-height-default" data-id="946b83d" data-element_type="section" data-e-type="section">
						<div class="elementor-container elementor-column-gap-default">
					<div class="elementor-column elementor-col-100 elementor-top-column elementor-element elementor-element-7d06dab" data-id="7d06dab" data-element_type="column" data-e-type="column">
			<div class="elementor-widget-wrap elementor-element-populated">
						<div class="elementor-element elementor-element-8695530 elementor-widget elementor-widget-code-highlight" data-id="8695530" data-element_type="widget" data-e-type="widget" data-widget_type="code-highlight.default">
				<div class="elementor-widget-container">
							<div class="prismjs-default copy-to-clipboard ">
			<pre data-line="" class="highlight-height language-javascript line-numbers">
				<code readonly="true" class="language-javascript">
					<xmp>            Task {
                await consume(i)
            }</xmp>
				</code>
			</pre>
		</div>
						</div>
				</div>
					</div>
		</div>
					</div>
		</section>
				<section class="elementor-section elementor-top-section elementor-element elementor-element-bb3db9d elementor-section-boxed elementor-section-height-default elementor-section-height-default" data-id="bb3db9d" data-element_type="section" data-e-type="section">
						<div class="elementor-container elementor-column-gap-default">
					<div class="elementor-column elementor-col-100 elementor-top-column elementor-element elementor-element-131748f" data-id="131748f" data-element_type="column" data-e-type="column">
			<div class="elementor-widget-wrap elementor-element-populated">
						<div class="elementor-element elementor-element-1d3adbb elementor-widget elementor-widget-text-editor" data-id="1d3adbb" data-element_type="widget" data-e-type="widget" data-widget_type="text-editor.default">
				<div class="elementor-widget-container">
									<p>What about <strong>@MainActor</strong>? Main actor&#8217;s work is executed on main queue which is serial:</p>								</div>
				</div>
					</div>
		</div>
					</div>
		</section>
				<section class="elementor-section elementor-top-section elementor-element elementor-element-98d5171 elementor-section-boxed elementor-section-height-default elementor-section-height-default" data-id="98d5171" data-element_type="section" data-e-type="section">
						<div class="elementor-container elementor-column-gap-default">
					<div class="elementor-column elementor-col-100 elementor-top-column elementor-element elementor-element-96615e3" data-id="96615e3" data-element_type="column" data-e-type="column">
			<div class="elementor-widget-wrap elementor-element-populated">
						<div class="elementor-element elementor-element-efdf2ad elementor-widget elementor-widget-code-highlight" data-id="efdf2ad" data-element_type="widget" data-e-type="widget" data-widget_type="code-highlight.default">
				<div class="elementor-widget-container">
							<div class="prismjs-default copy-to-clipboard ">
			<pre data-line="" class="highlight-height language-javascript line-numbers">
				<code readonly="true" class="language-javascript">
					<xmp>        Task { @MainActor in
            await consume(value)
        }</xmp>
				</code>
			</pre>
		</div>
						</div>
				</div>
					</div>
		</div>
					</div>
		</section>
				<section class="elementor-section elementor-top-section elementor-element elementor-element-523b296 elementor-section-boxed elementor-section-height-default elementor-section-height-default" data-id="523b296" data-element_type="section" data-e-type="section">
						<div class="elementor-container elementor-column-gap-default">
					<div class="elementor-column elementor-col-100 elementor-top-column elementor-element elementor-element-e95b0e8" data-id="e95b0e8" data-element_type="column" data-e-type="column">
			<div class="elementor-widget-wrap elementor-element-populated">
						<div class="elementor-element elementor-element-15cad3a elementor-widget elementor-widget-text-editor" data-id="15cad3a" data-element_type="widget" data-e-type="widget" data-widget_type="text-editor.default">
				<div class="elementor-widget-container">
									<p>It won&#8217;t work&nbsp;<span style="font-family: var( --e-global-typography-text-font-family ), Sans-serif;">either&nbsp;</span><span style="font-family: var( --e-global-typography-text-font-family ), Sans-serif;">because the task will be scheduled on a global executor, then execute its closure, realize it&#8217;s MainActor closure, and only then &#8216;hop&#8217; to MainActor.</span></p>
<p><span style="font-family: var( --e-global-typography-text-font-family ), Sans-serif;">Apple engineers are aware of those limitations and said that they are working on them.</span></p>
<p>Are there any remaining options? Yes &#8211; <strong>AsyncStream:</strong></p>								</div>
				</div>
					</div>
		</div>
					</div>
		</section>
				<section class="elementor-section elementor-top-section elementor-element elementor-element-44d286b elementor-section-boxed elementor-section-height-default elementor-section-height-default" data-id="44d286b" data-element_type="section" data-e-type="section">
						<div class="elementor-container elementor-column-gap-default">
					<div class="elementor-column elementor-col-100 elementor-top-column elementor-element elementor-element-f34d303" data-id="f34d303" data-element_type="column" data-e-type="column">
			<div class="elementor-widget-wrap elementor-element-populated">
						<div class="elementor-element elementor-element-d61d4da elementor-widget elementor-widget-code-highlight" data-id="d61d4da" data-element_type="widget" data-e-type="widget" data-widget_type="code-highlight.default">
				<div class="elementor-widget-container">
							<div class="prismjs-default copy-to-clipboard ">
			<pre data-line="" class="highlight-height language-javascript line-numbers">
				<code readonly="true" class="language-javascript">
					<xmp>func sendValues() {

        // Create async stream
        var continuation: AsyncStream<Int>.Continuation!
        self.stream = AsyncStream<Int>.init {
            continuation = $0
        }
        
        // Send values 'in order' to async stream
        for i in 0..<1000 {
            continuation.yield(i)
        }
        continuation.finish()
        
        // Consume values
        consume(stream: stream)
    }

    func consume(stream: AsyncStream<Int>) {
        Task {
            for await value in stream {
                print(value) // values received in order
            }
        }
    }
</xmp>
				</code>
			</pre>
		</div>
						</div>
				</div>
					</div>
		</div>
					</div>
		</section>
				</div>
		]]></content:encoded>
					
					<wfw:commentRss>https://iosdeveloperdiary.com/entering-async-await-task-from-synchronous-code-in-serial-manner/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>The myth about value and reference types</title>
		<link>https://iosdeveloperdiary.com/the-myth-about-value-and-reference-types/</link>
					<comments>https://iosdeveloperdiary.com/the-myth-about-value-and-reference-types/#respond</comments>
		
		<dc:creator><![CDATA[Tomasz]]></dc:creator>
		<pubDate>Mon, 24 Oct 2022 15:29:03 +0000</pubDate>
				<category><![CDATA[Uncategorized]]></category>
		<category><![CDATA[reference types value types swift]]></category>
		<guid isPermaLink="false">https://iosdeveloperdiary.com/?p=172</guid>

					<description><![CDATA[Remember myself trying to learn how iOS memory management works, few articles from the first pages of Google learned me that classes are deallocated by ARC when their reference count [&#8230;]]]></description>
										<content:encoded><![CDATA[		<div data-elementor-type="wp-post" data-elementor-id="172" class="elementor elementor-172" data-elementor-post-type="post">
						<section class="elementor-section elementor-top-section elementor-element elementor-element-8372cbf elementor-section-boxed elementor-section-height-default elementor-section-height-default" data-id="8372cbf" data-element_type="section" data-e-type="section">
						<div class="elementor-container elementor-column-gap-default">
					<div class="elementor-column elementor-col-100 elementor-top-column elementor-element elementor-element-541b228" data-id="541b228" data-element_type="column" data-e-type="column">
			<div class="elementor-widget-wrap elementor-element-populated">
						<div class="elementor-element elementor-element-6156051 elementor-widget elementor-widget-text-editor" data-id="6156051" data-element_type="widget" data-e-type="widget" data-widget_type="text-editor.default">
				<div class="elementor-widget-container">
									<p>Remember myself trying to learn how iOS memory management works, few articles from the first pages of Google learned me that classes are deallocated by ARC when their reference count equal 0, value types like structs, arrays, or strings are saved on the stack, reference values like classes and closures go into the heap, value types are better because stack allocation is faster, etc. And then thought to myself… ok! I got it! But in reality, is not that simple.</p>								</div>
				</div>
					</div>
		</div>
					</div>
		</section>
				<section class="elementor-section elementor-top-section elementor-element elementor-element-c7758ff elementor-section-boxed elementor-section-height-default elementor-section-height-default" data-id="c7758ff" data-element_type="section" data-e-type="section">
						<div class="elementor-container elementor-column-gap-default">
					<div class="elementor-column elementor-col-100 elementor-top-column elementor-element elementor-element-e3c11a5" data-id="e3c11a5" data-element_type="column" data-e-type="column">
			<div class="elementor-widget-wrap elementor-element-populated">
						<div class="elementor-element elementor-element-4b32199 elementor-widget elementor-widget-text-editor" data-id="4b32199" data-element_type="widget" data-e-type="widget" data-widget_type="text-editor.default">
				<div class="elementor-widget-container">
									<p>Let’s see Apple’s definition of value and reference type:</p><p><b><em>Value type</em> &#8211; </b><em>A value type is a type whose value is copied when it’s assigned to a variable or constant, or when it’s passed to a function.</em></p><p><b><em>Reference type</em> &#8211; </b><em>Unlike value types, reference types are not copied when they’re assigned to a variable or constant, or when they’re passed to a function. Rather than a copy, a reference to the same existing instance is used.</em></p>								</div>
				</div>
					</div>
		</div>
					</div>
		</section>
				<section class="elementor-section elementor-top-section elementor-element elementor-element-6755808 elementor-section-boxed elementor-section-height-default elementor-section-height-default" data-id="6755808" data-element_type="section" data-e-type="section">
						<div class="elementor-container elementor-column-gap-default">
					<div class="elementor-column elementor-col-100 elementor-top-column elementor-element elementor-element-3e0040c" data-id="3e0040c" data-element_type="column" data-e-type="column">
			<div class="elementor-widget-wrap elementor-element-populated">
						<div class="elementor-element elementor-element-11659ec elementor-widget elementor-widget-text-editor" data-id="11659ec" data-element_type="widget" data-e-type="widget" data-widget_type="text-editor.default">
				<div class="elementor-widget-container">
									<p>As we can see those definitions only specify how types are passed around, there is not a single word about the place they will be stored, they can be stored on the stack or the heap or even &#8216;both&#8217;, this is just an implementation detail.</p>
<p>There are some cases when a value type is passed by reference, to accomplish additional functionality for a Swift language or just as an optimization, there are two well known cases:</p>
<p>1. Passing value type into a closure:</p>								</div>
				</div>
				<div class="elementor-element elementor-element-36d7dc2 elementor-widget elementor-widget-code-highlight" data-id="36d7dc2" data-element_type="widget" data-e-type="widget" data-widget_type="code-highlight.default">
				<div class="elementor-widget-container">
							<div class="prismjs-default  ">
			<pre data-line="" class="highlight-height language-swift ">
				<code readonly="true" class="language-swift">
					<xmp> var name: String = "Bob"

DispatchQueue.global().asyncAfter(deadline: .now() + 1) {
    print(name) // prints "Muniek" - name variable is captured be a reference not a copy.
}

name = "Muniek"</xmp>
				</code>
			</pre>
		</div>
						</div>
				</div>
				<div class="elementor-element elementor-element-e8b4575 elementor-widget elementor-widget-text-editor" data-id="e8b4575" data-element_type="widget" data-e-type="widget" data-widget_type="text-editor.default">
				<div class="elementor-widget-container">
									<p>Why? This is just how Swift was implemented, be default closure capture value by reference, or better said, capture variable by reference, you can use capture list to change that.<span class="Apple-converted-space"> </span></p>
<p>This is one of Swift’s creators explaining why it works that way:</p>								</div>
				</div>
				<div class="elementor-element elementor-element-c72df75 elementor-widget elementor-widget-image" data-id="c72df75" data-element_type="widget" data-e-type="widget" data-widget_type="image.default">
				<div class="elementor-widget-container">
															<img fetchpriority="high" decoding="async" width="768" height="177" src="https://iosdeveloperdiary.com/wp-content/uploads/2022/10/Zrzut-ekranu-2022-10-22-o-17.45.35-768x177.png" class="attachment-medium_large size-medium_large wp-image-184" alt="" srcset="https://iosdeveloperdiary.com/wp-content/uploads/2022/10/Zrzut-ekranu-2022-10-22-o-17.45.35-768x177.png 768w, https://iosdeveloperdiary.com/wp-content/uploads/2022/10/Zrzut-ekranu-2022-10-22-o-17.45.35-300x69.png 300w, https://iosdeveloperdiary.com/wp-content/uploads/2022/10/Zrzut-ekranu-2022-10-22-o-17.45.35-1024x236.png 1024w, https://iosdeveloperdiary.com/wp-content/uploads/2022/10/Zrzut-ekranu-2022-10-22-o-17.45.35-1536x354.png 1536w, https://iosdeveloperdiary.com/wp-content/uploads/2022/10/Zrzut-ekranu-2022-10-22-o-17.45.35.png 1538w" sizes="(max-width: 768px) 100vw, 768px" />															</div>
				</div>
				<div class="elementor-element elementor-element-a47f67c elementor-widget elementor-widget-text-editor" data-id="a47f67c" data-element_type="widget" data-e-type="widget" data-widget_type="text-editor.default">
				<div class="elementor-widget-container">
									<p>2 . Array is a value type but passed by reference not a copy, an actual copy of an array is made when mutation of this array occurs, this is an optimization to reduce copying large amounts of data as arrays can have thousands of items inside. This optimization is called Copy on write (COW). Underneath it behaves like a reference type violating the definition of value type but when you want to edit it, it will make a copy. Maybe that is the reason why Apple likes to refer to value types as „value type SEMANTICS” &#8211; they behave as value type on the surface, but what is underneath is again… implementation detail.</p>
<p> </p>								</div>
				</div>
				<div class="elementor-element elementor-element-31fa04e elementor-widget elementor-widget-text-editor" data-id="31fa04e" data-element_type="widget" data-e-type="widget" data-widget_type="text-editor.default">
				<div class="elementor-widget-container">
									<h4><b>When type is allocated on the heap and when on the stack?</b></h4>								</div>
				</div>
				<div class="elementor-element elementor-element-f93edc9 elementor-widget elementor-widget-text-editor" data-id="f93edc9" data-element_type="widget" data-e-type="widget" data-widget_type="text-editor.default">
				<div class="elementor-widget-container">
									<p>I’m sure you heard that stack allocation and deallocation are fast so the best precise will be to allocate everything on the stack, but it is impossible because of the way the stack works.</p>
<p>Generally, two things imply whether something is allocated on the heap:</p>
<p><b>1. when something has to outlive the scope it was created in<br /></b>You can only put and pop from the stack, imagine a variable created inside some function. If this variable (THIS variable instance not a copy) has to be accessible after the function exits, it cannot be stored on the stack, because there will be other function-related stuff saved, so to deallocate function call and save THIS variable, the compiler will need to pop all function data and push THIS variable again on top, which may not seem like a lot of work but image function calling another function and this function calls another and another and every single function want to have some local variables by accessible outside their scope, this will require a lot of stack memory juggling &#8211; it is just not practical so better way is to allocate this variable on the heap and pass a reference to it.</p>
<p><b>2. when something may change its size<br /></b>Imagine a function that has two local variables: String and Int</p>								</div>
				</div>
				<div class="elementor-element elementor-element-6242175 elementor-widget elementor-widget-code-highlight" data-id="6242175" data-element_type="widget" data-e-type="widget" data-widget_type="code-highlight.default">
				<div class="elementor-widget-container">
							<div class="prismjs-default  ">
			<pre data-line="" class="highlight-height language-swift ">
				<code readonly="true" class="language-swift">
					<xmp>func someFunction() {
   var name: String = "Muniek"
   var age: Int = 30
}
</xmp>
				</code>
			</pre>
		</div>
						</div>
				</div>
				<div class="elementor-element elementor-element-e4a0678 elementor-widget elementor-widget-text-editor" data-id="e4a0678" data-element_type="widget" data-e-type="widget" data-widget_type="text-editor.default">
				<div class="elementor-widget-container">
									<p>Runtime compiler will allocate memory for those variables on the stack like so:</p>								</div>
				</div>
					</div>
		</div>
					</div>
		</section>
				<section class="elementor-section elementor-top-section elementor-element elementor-element-0f8ae59 elementor-section-content-bottom elementor-section-boxed elementor-section-height-default elementor-section-height-default" data-id="0f8ae59" data-element_type="section" data-e-type="section">
						<div class="elementor-container elementor-column-gap-default">
					<div class="elementor-column elementor-col-50 elementor-top-column elementor-element elementor-element-e8f6863" data-id="e8f6863" data-element_type="column" data-e-type="column">
			<div class="elementor-widget-wrap elementor-element-populated">
						<div class="elementor-element elementor-element-0e383c5 elementor-widget elementor-widget-image" data-id="0e383c5" data-element_type="widget" data-e-type="widget" data-widget_type="image.default">
				<div class="elementor-widget-container">
															<img decoding="async" width="176" height="300" src="https://iosdeveloperdiary.com/wp-content/uploads/2022/10/Zrzut-ekranu-2022-10-24-o-17.16.27-1-176x300.png" class="attachment-medium size-medium wp-image-191" alt="" srcset="https://iosdeveloperdiary.com/wp-content/uploads/2022/10/Zrzut-ekranu-2022-10-24-o-17.16.27-1-176x300.png 176w, https://iosdeveloperdiary.com/wp-content/uploads/2022/10/Zrzut-ekranu-2022-10-24-o-17.16.27-1.png 318w" sizes="(max-width: 176px) 100vw, 176px" />															</div>
				</div>
					</div>
		</div>
				<div class="elementor-column elementor-col-50 elementor-top-column elementor-element elementor-element-c98b76a" data-id="c98b76a" data-element_type="column" data-e-type="column">
			<div class="elementor-widget-wrap elementor-element-populated">
						<div class="elementor-element elementor-element-9a56356 elementor-widget elementor-widget-text-editor" data-id="9a56356" data-element_type="widget" data-e-type="widget" data-widget_type="text-editor.default">
				<div class="elementor-widget-container">
									<p><em>(This is just a simplified demonstration, in reality, the whole name will be allocated in a single line/word)</em></p>								</div>
				</div>
					</div>
		</div>
					</div>
		</section>
				<section class="elementor-section elementor-top-section elementor-element elementor-element-138f23f elementor-section-boxed elementor-section-height-default elementor-section-height-default" data-id="138f23f" data-element_type="section" data-e-type="section">
						<div class="elementor-container elementor-column-gap-default">
					<div class="elementor-column elementor-col-100 elementor-top-column elementor-element elementor-element-80d1f67" data-id="80d1f67" data-element_type="column" data-e-type="column">
			<div class="elementor-widget-wrap elementor-element-populated">
						<div class="elementor-element elementor-element-0a11a62 elementor-widget elementor-widget-text-editor" data-id="0a11a62" data-element_type="widget" data-e-type="widget" data-widget_type="text-editor.default">
				<div class="elementor-widget-container">
									<p>Then if the function wants to change the name variable for something longer, again, the stack will have to pop all data up to the „name” variable, push a new string and other values again &#8211; which is not a quick way.</p>
<p>To be more precise, the compiler allocates some fixed amount of memory for a string variable, whether it is a single letter „A” or a name „Michael” String will take the same amount of memory on the stack, so some mutation is possible on the stack, but when string becomes longer, the whole string is moved into the heap and only reference to this memory is kept o the stack. Similarly, arrays that are value type but values inside an array are kept on the heap.</p>
<p>So if those two cases don’t occur, everything is allocated on the stack, right? What about class? If we create an immutable instance of a simple class, will it be stored on the stack?</p>								</div>
				</div>
				<div class="elementor-element elementor-element-2433bf5 elementor-widget elementor-widget-code-highlight" data-id="2433bf5" data-element_type="widget" data-e-type="widget" data-widget_type="code-highlight.default">
				<div class="elementor-widget-container">
							<div class="prismjs-default  ">
			<pre data-line="" class="highlight-height language-swift ">
				<code readonly="true" class="language-swift">
					<xmp>class Person {
    let name: String = "Muniek"
}

func someFunction() {
   let person = Person() // heap
}</xmp>
				</code>
			</pre>
		</div>
						</div>
				</div>
				<div class="elementor-element elementor-element-621c58b elementor-widget elementor-widget-text-editor" data-id="621c58b" data-element_type="widget" data-e-type="widget" data-widget_type="text-editor.default">
				<div class="elementor-widget-container">
									<p>It will be allocated on the heap. Why not on the stack? It will be really quick and just better, I do not know the answer, maybe Swift will implement this type of optimization in the future or maybe that type of optimization will prevent some other optimizations and they choose not to do it?</p>
<p> </p>								</div>
				</div>
				<div class="elementor-element elementor-element-6414021 elementor-widget elementor-widget-text-editor" data-id="6414021" data-element_type="widget" data-e-type="widget" data-widget_type="text-editor.default">
				<div class="elementor-widget-container">
									<h4><b>Reference type inside value type</b></h4>								</div>
				</div>
				<div class="elementor-element elementor-element-1eb87c6 elementor-widget elementor-widget-text-editor" data-id="1eb87c6" data-element_type="widget" data-e-type="widget" data-widget_type="text-editor.default">
				<div class="elementor-widget-container">
									<p><span style="color: var( --e-global-color-text ); font-family: var( --e-global-typography-text-font-family ), Sans-serif;">Swift likes value types like structs, they are most likely stored on the stack and do not have shared instance which Apple always refer to as a cause of „unintended sharing of state”</span></p>
<p>So are structs always a better choice? Not really… just look at the example with arrays and COW we discussed earlier or this struct which contains a bunch of classes as members:</p>								</div>
				</div>
				<div class="elementor-element elementor-element-6b28583 elementor-widget elementor-widget-code-highlight" data-id="6b28583" data-element_type="widget" data-e-type="widget" data-widget_type="code-highlight.default">
				<div class="elementor-widget-container">
							<div class="prismjs-default  ">
			<pre data-line="" class="highlight-height language-swift ">
				<code readonly="true" class="language-swift">
					<xmp>struct SomeType {
    var age: Int

    var object: SomeClass
    var object: SomeClass
    var object: SomeClass
    var object: SomeClass
    var object: SomeClass
}</xmp>
				</code>
			</pre>
		</div>
						</div>
				</div>
				<div class="elementor-element elementor-element-f583d5b elementor-widget elementor-widget-text-editor" data-id="f583d5b" data-element_type="widget" data-e-type="widget" data-widget_type="text-editor.default">
				<div class="elementor-widget-container">
									<p>Struct being value type is passed as a copy but what about reference types inside? They will be passed as a reference, or better said copy of a reference increasing the reference count of every single one of them. Every time we pass this struct compiler needs to increase the reference count, which again… doesn’t look like much work, but on a larger scale it may sum up to milliseconds or even seconds!<span class="Apple-converted-space"> </span></p>
<p>Let’s change SomeType to be a class &#8211; every time you pass this object only one reference count needs to be increased, there is no need to change the reference count of every reference type member.</p>
<p> </p>								</div>
				</div>
				<div class="elementor-element elementor-element-98f8ef6 elementor-widget elementor-widget-text-editor" data-id="98f8ef6" data-element_type="widget" data-e-type="widget" data-widget_type="text-editor.default">
				<div class="elementor-widget-container">
									<h4><b>Value type in a reference type</b></h4>								</div>
				</div>
				<div class="elementor-element elementor-element-c9ab5de elementor-widget elementor-widget-code-highlight" data-id="c9ab5de" data-element_type="widget" data-e-type="widget" data-widget_type="code-highlight.default">
				<div class="elementor-widget-container">
							<div class="prismjs-default  ">
			<pre data-line="" class="highlight-height language-swift ">
				<code readonly="true" class="language-swift">
					<xmp>struct SomeStruct {
    var name: String
}
        
class SomeClass {
    var someStruct: SomeStruct = .init(name: "Muniek")
}</xmp>
				</code>
			</pre>
		</div>
						</div>
				</div>
				<div class="elementor-element elementor-element-14e130f elementor-widget elementor-widget-text-editor" data-id="14e130f" data-element_type="widget" data-e-type="widget" data-widget_type="text-editor.default">
				<div class="elementor-widget-container">
									<p>In this situation, the value type struct will be saved where the class is, on the heap. Passing SomeClass to another function will pass a reference to this class and give access to the same struct:</p>								</div>
				</div>
				<div class="elementor-element elementor-element-4755927 elementor-widget elementor-widget-code-highlight" data-id="4755927" data-element_type="widget" data-e-type="widget" data-widget_type="code-highlight.default">
				<div class="elementor-widget-container">
							<div class="prismjs-default  ">
			<pre data-line="" class="highlight-height language-swift ">
				<code readonly="true" class="language-swift">
					<xmp>let someClass = SomeClass()
print(someClass.someStruct.name) // Muniek
        
func rename(_ someClass: SomeClass) {
   someClass.someStruct.name = "Bob"
}
        
rename(someClass)
print(someClass.someStruct.name) // Bob</xmp>
				</code>
			</pre>
		</div>
						</div>
				</div>
					</div>
		</div>
					</div>
		</section>
				</div>
		]]></content:encoded>
					
					<wfw:commentRss>https://iosdeveloperdiary.com/the-myth-about-value-and-reference-types/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>Collecting logs from physical device after UI and Unit tests on CI machine (Fastlane, Jenkins)</title>
		<link>https://iosdeveloperdiary.com/collecting-logs-from-physical-device-after-ui-and-unit-tests-on-ci-machine-fastlane-jenkins/</link>
					<comments>https://iosdeveloperdiary.com/collecting-logs-from-physical-device-after-ui-and-unit-tests-on-ci-machine-fastlane-jenkins/#respond</comments>
		
		<dc:creator><![CDATA[Tomasz]]></dc:creator>
		<pubDate>Wed, 24 Aug 2022 15:33:27 +0000</pubDate>
				<category><![CDATA[Uncategorized]]></category>
		<category><![CDATA[Fastlane]]></category>
		<category><![CDATA[iOS]]></category>
		<category><![CDATA[Jenkins]]></category>
		<category><![CDATA[Physical device logs]]></category>
		<category><![CDATA[Swift]]></category>
		<guid isPermaLink="false">https://iosdeveloperdiary.com/?p=198</guid>

					<description><![CDATA[UI and Unit automated tests are great when they pass and everything is green, the problem appears when some tests fail and we need to know why. Some tests may [&#8230;]]]></description>
										<content:encoded><![CDATA[		<div data-elementor-type="wp-post" data-elementor-id="198" class="elementor elementor-198" data-elementor-post-type="post">
						<section class="elementor-section elementor-top-section elementor-element elementor-element-fe1a406 elementor-section-boxed elementor-section-height-default elementor-section-height-default" data-id="fe1a406" data-element_type="section" data-e-type="section">
						<div class="elementor-container elementor-column-gap-default">
					<div class="elementor-column elementor-col-100 elementor-top-column elementor-element elementor-element-7437c3b" data-id="7437c3b" data-element_type="column" data-e-type="column">
			<div class="elementor-widget-wrap elementor-element-populated">
						<div class="elementor-element elementor-element-bcaf2cc elementor-widget elementor-widget-text-editor" data-id="bcaf2cc" data-element_type="widget" data-e-type="widget" data-widget_type="text-editor.default">
				<div class="elementor-widget-container">
									<p>UI and Unit automated tests are great when they pass and everything is green, the problem appears when some tests fail and we need to know why. Some tests may fail once per 100 runs, especially UI integration tests and simply running them again may not give us any answers, those flaky tests are the reasons why sometimes we put a blind eye to them just because it is too much of a hassle.</p>								</div>
				</div>
				<div class="elementor-element elementor-element-c1f7409 elementor-widget elementor-widget-text-editor" data-id="c1f7409" data-element_type="widget" data-e-type="widget" data-widget_type="text-editor.default">
				<div class="elementor-widget-container">
									<p>1. Logging messages in the application code<br />2. Setting up UI/Unit tests observers<br />3. Categorize logs based on current Unit test<br />4. Categorize logs based on current UI test<br />5. Collecting logs after tests with Simulator<br />6. Collecting logs after tests with physical device<br />7. Getting logs from CI to Jenkins<br />8. Browsing through logs</p>								</div>
				</div>
				<div class="elementor-element elementor-element-662fdd3 elementor-widget elementor-widget-text-editor" data-id="662fdd3" data-element_type="widget" data-e-type="widget" data-widget_type="text-editor.default">
				<div class="elementor-widget-container">
									<h4>Logging messages in the application code</h4>								</div>
				</div>
				<div class="elementor-element elementor-element-07325cf elementor-widget elementor-widget-text-editor" data-id="07325cf" data-element_type="widget" data-e-type="widget" data-widget_type="text-editor.default">
				<div class="elementor-widget-container">
									<p>For logging, we are gonna use <em><strong>Logger</strong></em> from <strong>os</strong> module which is an Apple unified logging system.</p><p>First, we need to import <em><strong>os</strong></em> module and create and Logger structure. The initializer takes two parameters, subsystem, and category which are useful for filtering log messages.</p><p>In this article, we will only use category but maybe you would like to set subsystem as Test Suite’s name and Test Case’s name as the category, it is up to you.</p>								</div>
				</div>
				<div class="elementor-element elementor-element-5c4cb90 elementor-widget elementor-widget-code-highlight" data-id="5c4cb90" data-element_type="widget" data-e-type="widget" data-widget_type="code-highlight.default">
				<div class="elementor-widget-container">
							<div class="prismjs-default  ">
			<pre data-line="" class="highlight-height language-swift ">
				<code readonly="true" class="language-swift">
					<xmp>import os
internal var logger = Logger(subsystem: "com.company.sampleApplication", category: "category")</xmp>
				</code>
			</pre>
		</div>
						</div>
				</div>
				<div class="elementor-element elementor-element-aac0848 elementor-widget elementor-widget-text-editor" data-id="aac0848" data-element_type="widget" data-e-type="widget" data-widget_type="text-editor.default">
				<div class="elementor-widget-container">
									<p>The logger must be globally accessible and declared as a variable, in order to be able to change its category accordingly to current test, we will get back to it later.</p>								</div>
				</div>
				<div class="elementor-element elementor-element-b14da26 elementor-widget elementor-widget-code-highlight" data-id="b14da26" data-element_type="widget" data-e-type="widget" data-widget_type="code-highlight.default">
				<div class="elementor-widget-container">
							<div class="prismjs-default  ">
			<pre data-line="" class="highlight-height language-swift ">
				<code readonly="true" class="language-swift">
					<xmp>// Log error message example:
logger.error("Error occurred!")</xmp>
				</code>
			</pre>
		</div>
						</div>
				</div>
				<div class="elementor-element elementor-element-c86022b elementor-widget elementor-widget-text-editor" data-id="c86022b" data-element_type="widget" data-e-type="widget" data-widget_type="text-editor.default">
				<div class="elementor-widget-container">
									<p>you can read more about <em><strong>Logger</strong></em> here:<br /><a href="https://developer.apple.com/documentation/os/logger" target="_blank" rel="noopener">https://developer.apple.com/documentation/os/logger</a></p>								</div>
				</div>
				<div class="elementor-element elementor-element-ee0e0a1 elementor-widget elementor-widget-text-editor" data-id="ee0e0a1" data-element_type="widget" data-e-type="widget" data-widget_type="text-editor.default">
				<div class="elementor-widget-container">
									<p><em>The logger has typical log levels debug, info, notice, error, and fault.</em><br /><em>With default logging system configuration low priority levels (debug and info) aren’t stored in phone’s persistent memory, they are available only during app’s live cycle, so the best way is to only use notice, error, and failure for important messages.</em></p>								</div>
				</div>
				<div class="elementor-element elementor-element-e61e492 elementor-widget elementor-widget-text-editor" data-id="e61e492" data-element_type="widget" data-e-type="widget" data-widget_type="text-editor.default">
				<div class="elementor-widget-container">
									<p>You can use logger alongside other logging engines, I personally like to use <em><strong>SwiftyBeaver</strong></em> as the main application logging system as it has some useful built-in features and a simple way to add new logging methods:</p>								</div>
				</div>
				<div class="elementor-element elementor-element-1aa630e elementor-widget elementor-widget-code-highlight" data-id="1aa630e" data-element_type="widget" data-e-type="widget" data-widget_type="code-highlight.default">
				<div class="elementor-widget-container">
							<div class="prismjs-default  ">
			<pre data-line="" class="highlight-height language-swift ">
				<code readonly="true" class="language-swift">
					<xmp>class OsLoggerDestination: BaseDestination {
    override open func send(_ level: SwiftyBeaver.Level, msg: String, thread: String, file: String, function: String, line: Int, context: Any? = nil) -> String? {

        let formattedString = super.send(level, msg: msg, thread: thread, file: file, function: function, line: line, context: context) ?? ""
        
        switch level {
        case .debug, .info, .verbose:
            logger.notice("\(formattedString, privacy: .public)")
            
        case .warning:
            logger.error("\(formattedString, privacy: .public)")
            
        case .error:
            logger.fault("\(formattedString, privacy: .public)")
        }
        
        return formattedString
    }
}

SwiftyBeaver.addDestination(OsLoggerDestination())</xmp>
				</code>
			</pre>
		</div>
						</div>
				</div>
				<div class="elementor-element elementor-element-4ee1292 elementor-widget elementor-widget-text-editor" data-id="4ee1292" data-element_type="widget" data-e-type="widget" data-widget_type="text-editor.default">
				<div class="elementor-widget-container">
									<h4>Setting up UI/Unit tests observers</h4>								</div>
				</div>
				<div class="elementor-element elementor-element-6a94708 elementor-widget elementor-widget-text-editor" data-id="6a94708" data-element_type="widget" data-e-type="widget" data-widget_type="text-editor.default">
				<div class="elementor-widget-container">
									<p>XCTest module contains a delegate protocol named <em><strong>XCTestObservation</strong></em> which is called during a test execution cycle, e.g before each test starts or after its failure.</p><p>In order for it to work we need to create two classes that implement this protocol, <em><strong>UnitTestDelegate</strong></em>, and <em><strong>UITestDelegate</strong></em>:</p>								</div>
				</div>
				<div class="elementor-element elementor-element-a782096 elementor-widget elementor-widget-code-highlight" data-id="a782096" data-element_type="widget" data-e-type="widget" data-widget_type="code-highlight.default">
				<div class="elementor-widget-container">
							<div class="prismjs-default  ">
			<pre data-line="" class="highlight-height language-swift ">
				<code readonly="true" class="language-swift">
					<xmp>import XCTest

class ____TestDelegate: NSObject, XCTestObservation {
    
    func testBundleDidFinish(_ testBundle: Bundle) {
        XCTestObservationCenter.shared.removeTestObserver(self)
    }
    
    override init() {
        super.init()
        XCTestObservationCenter.shared.addTestObserver(self)
    }

    func testCaseWillStart(_ testCase: XCTestCase) {
        // Called before each test
    }
}</xmp>
				</code>
			</pre>
		</div>
						</div>
				</div>
				<div class="elementor-element elementor-element-3362279 elementor-widget elementor-widget-text-editor" data-id="3362279" data-element_type="widget" data-e-type="widget" data-widget_type="text-editor.default">
				<div class="elementor-widget-container">
									<p>and set them as the <strong><em>Principal</em> <em>class </em></strong>of each test targets <em><strong>info.plist</strong></em>:</p>								</div>
				</div>
				<div class="elementor-element elementor-element-ef79fbb elementor-widget elementor-widget-image" data-id="ef79fbb" data-element_type="widget" data-e-type="widget" data-widget_type="image.default">
				<div class="elementor-widget-container">
															<img decoding="async" width="790" height="135" src="https://iosdeveloperdiary.com/wp-content/uploads/2022/10/Zrzut-ekranu-2022-09-5-o-08.41.42-1024x175.png" class="attachment-large size-large wp-image-246" alt="" srcset="https://iosdeveloperdiary.com/wp-content/uploads/2022/10/Zrzut-ekranu-2022-09-5-o-08.41.42-1024x175.png 1024w, https://iosdeveloperdiary.com/wp-content/uploads/2022/10/Zrzut-ekranu-2022-09-5-o-08.41.42-300x51.png 300w, https://iosdeveloperdiary.com/wp-content/uploads/2022/10/Zrzut-ekranu-2022-09-5-o-08.41.42-768x131.png 768w, https://iosdeveloperdiary.com/wp-content/uploads/2022/10/Zrzut-ekranu-2022-09-5-o-08.41.42.png 1438w" sizes="(max-width: 790px) 100vw, 790px" />															</div>
				</div>
				<div class="elementor-element elementor-element-5209670 elementor-widget elementor-widget-image" data-id="5209670" data-element_type="widget" data-e-type="widget" data-widget_type="image.default">
				<div class="elementor-widget-container">
															<img loading="lazy" decoding="async" width="790" height="132" src="https://iosdeveloperdiary.com/wp-content/uploads/2022/10/Zrzut-ekranu-2022-09-5-o-08.45.37-1024x171.png" class="attachment-large size-large wp-image-247" alt="" srcset="https://iosdeveloperdiary.com/wp-content/uploads/2022/10/Zrzut-ekranu-2022-09-5-o-08.45.37-1024x171.png 1024w, https://iosdeveloperdiary.com/wp-content/uploads/2022/10/Zrzut-ekranu-2022-09-5-o-08.45.37-300x50.png 300w, https://iosdeveloperdiary.com/wp-content/uploads/2022/10/Zrzut-ekranu-2022-09-5-o-08.45.37-768x128.png 768w, https://iosdeveloperdiary.com/wp-content/uploads/2022/10/Zrzut-ekranu-2022-09-5-o-08.45.37.png 1402w" sizes="(max-width: 790px) 100vw, 790px" />															</div>
				</div>
				<div class="elementor-element elementor-element-2b446a3 elementor-widget elementor-widget-text-editor" data-id="2b446a3" data-element_type="widget" data-e-type="widget" data-widget_type="text-editor.default">
				<div class="elementor-widget-container">
									<h4>Categorize logs based on current Unit test</h4>								</div>
				</div>
				<div class="elementor-element elementor-element-64f3a29 elementor-widget elementor-widget-text-editor" data-id="64f3a29" data-element_type="widget" data-e-type="widget" data-widget_type="text-editor.default">
				<div class="elementor-widget-container">
									<p>Our goal here is to set the test case name as a logger category. With <em><strong>@testable import</strong></em> inside Unit Test Target we can access application internal variables, in this case from <em><strong>testCaseWillStart</strong></em> function inside <em><strong>UnitTestDelegate</strong></em> we can set up our application logger accordingly:</p>								</div>
				</div>
				<div class="elementor-element elementor-element-2c7261f elementor-widget elementor-widget-code-highlight" data-id="2c7261f" data-element_type="widget" data-e-type="widget" data-widget_type="code-highlight.default">
				<div class="elementor-widget-container">
							<div class="prismjs-default  ">
			<pre data-line="" class="highlight-height language-swift ">
				<code readonly="true" class="language-swift">
					<xmp>@testable import SampleApplication
import os

func testCaseWillStart(_ testCase: XCTestCase) {
    logger = Logger(subsystem: "com.sample.sampleApplication", category: testCase.name)
}</xmp>
				</code>
			</pre>
		</div>
						</div>
				</div>
				<div class="elementor-element elementor-element-ecd8aed elementor-widget elementor-widget-text-editor" data-id="ecd8aed" data-element_type="widget" data-e-type="widget" data-widget_type="text-editor.default">
				<div class="elementor-widget-container">
									<h4>Categorize logs based on current UI test</h4>								</div>
				</div>
				<div class="elementor-element elementor-element-788c192 elementor-widget elementor-widget-text-editor" data-id="788c192" data-element_type="widget" data-e-type="widget" data-widget_type="text-editor.default">
				<div class="elementor-widget-container">
									<p>UI Test target doesn’t have access to any of the application properties so we need to send the test case name from the test to an application. We can use <em><strong>launchEnvironments</strong></em> by setting their test name under some key then accessing it inside the application code in <em><strong>didFinishLaunchingWithOptions</strong></em> and setup our logger category:</p><p>inside <em><strong>testCaseWillStart</strong></em> function of <em><strong>UITestDelegate</strong></em> class:</p>								</div>
				</div>
				<div class="elementor-element elementor-element-2a55405 elementor-widget elementor-widget-code-highlight" data-id="2a55405" data-element_type="widget" data-e-type="widget" data-widget_type="code-highlight.default">
				<div class="elementor-widget-container">
							<div class="prismjs-default  ">
			<pre data-line="" class="highlight-height language-swift ">
				<code readonly="true" class="language-swift">
					<xmp>    func testCaseWillStart(_ testCase: XCTestCase) {
        app.launchEnvironment["TEST_NAME"] = testCase.name
    }</xmp>
				</code>
			</pre>
		</div>
						</div>
				</div>
				<div class="elementor-element elementor-element-015f76c elementor-widget elementor-widget-text-editor" data-id="015f76c" data-element_type="widget" data-e-type="widget" data-widget_type="text-editor.default">
				<div class="elementor-widget-container">
									<p>and then in the application’s <em><strong>AppDelegate</strong></em>:</p>								</div>
				</div>
				<div class="elementor-element elementor-element-1614c56 elementor-widget elementor-widget-code-highlight" data-id="1614c56" data-element_type="widget" data-e-type="widget" data-widget_type="code-highlight.default">
				<div class="elementor-widget-container">
							<div class="prismjs-default  ">
			<pre data-line="" class="highlight-height language-swift ">
				<code readonly="true" class="language-swift">
					<xmp>    func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {

        if let testName = ProcessInfo.processInfo.environment["TEST_NAME"] {
            logger = Logger(subsystem: "com.company.sampleApplication", category: testName)
        }

        return true
    }</xmp>
				</code>
			</pre>
		</div>
						</div>
				</div>
				<div class="elementor-element elementor-element-e9dd3ea elementor-widget elementor-widget-text-editor" data-id="e9dd3ea" data-element_type="widget" data-e-type="widget" data-widget_type="text-editor.default">
				<div class="elementor-widget-container">
									<h4>Collecting logs after tests with Simulator</h4>								</div>
				</div>
				<div class="elementor-element elementor-element-24d3c34 elementor-widget elementor-widget-text-editor" data-id="24d3c34" data-element_type="widget" data-e-type="widget" data-widget_type="text-editor.default">
				<div class="elementor-widget-container">
									<p>It is pretty easy with simulator because in <em><strong>Fastlane</strong></em> we need to set just two parameters in the scan suite <strong><em>run_tests</em> </strong>function:</p><p><em><strong>output_directory</strong></em> &#8211; <em>The directory in which all reports will be stored</em><br /><em><strong>include_simulator_logs</strong></em> &#8211; <em>whether the logs generated by the app in the Simulator should be written to the output_directory</em></p>								</div>
				</div>
				<div class="elementor-element elementor-element-652bf5e elementor-widget elementor-widget-text-editor" data-id="652bf5e" data-element_type="widget" data-e-type="widget" data-widget_type="text-editor.default">
				<div class="elementor-widget-container">
									<h4>Collecting logs after tests with physical device</h4>								</div>
				</div>
				<div class="elementor-element elementor-element-6c88784 elementor-widget elementor-widget-text-editor" data-id="6c88784" data-element_type="widget" data-e-type="widget" data-widget_type="text-editor.default">
				<div class="elementor-widget-container">
									<p>In order to retrieve logs from a physical device we will use the <em><strong>log</strong></em> tool as recommended by Apple here:</p><p><a href="https://developer.apple.com/documentation/os/logging/viewing_log_messages" target="_blank" rel="noopener">https://developer.apple.com/documentation/os/logging/viewing_log_messages</a></p><p>One downside of this approach is this command requires <em><strong>sudo privileges</strong></em>, which may be problematic on CI environments but not impossible e.g. by responsibly editing <em><strong>sudoers</strong></em> file.</p><p>first, in <em><strong>Fastfile</strong></em> we need to save test start time:</p>								</div>
				</div>
				<div class="elementor-element elementor-element-3431ed1 elementor-widget elementor-widget-code-highlight" data-id="3431ed1" data-element_type="widget" data-e-type="widget" data-widget_type="code-highlight.default">
				<div class="elementor-widget-container">
							<div class="prismjs-default  ">
			<pre data-line="" class="highlight-height language-bash ">
				<code readonly="true" class="language-bash">
					<xmp>start_time = "@#{Time.now.to_i}"</xmp>
				</code>
			</pre>
		</div>
						</div>
				</div>
				<div class="elementor-element elementor-element-7b198c1 elementor-widget elementor-widget-text-editor" data-id="7b198c1" data-element_type="widget" data-e-type="widget" data-widget_type="text-editor.default">
				<div class="elementor-widget-container">
									<p>and then collect logs after tests execution:</p>								</div>
				</div>
				<div class="elementor-element elementor-element-5531a71 elementor-widget elementor-widget-code-highlight" data-id="5531a71" data-element_type="widget" data-e-type="widget" data-widget_type="code-highlight.default">
				<div class="elementor-widget-container">
							<div class="prismjs-default  ">
			<pre data-line="" class="highlight-height language-bash ">
				<code readonly="true" class="language-bash">
					<xmp>sh "sudo log collect --device-udid 'xxxxxxxx' --start #{start_time} --output ./mylogs.logarchive"</xmp>
				</code>
			</pre>
		</div>
						</div>
				</div>
				<div class="elementor-element elementor-element-0cc62f2 elementor-widget elementor-widget-text-editor" data-id="0cc62f2" data-element_type="widget" data-e-type="widget" data-widget_type="text-editor.default">
				<div class="elementor-widget-container">
									<h4>Getting logs from CI to Jenkins</h4>								</div>
				</div>
				<div class="elementor-element elementor-element-d8eb662 elementor-widget elementor-widget-text-editor" data-id="d8eb662" data-element_type="widget" data-e-type="widget" data-widget_type="text-editor.default">
				<div class="elementor-widget-container">
									<p>zip logarchive by:</p>								</div>
				</div>
				<div class="elementor-element elementor-element-3050e6f elementor-widget elementor-widget-code-highlight" data-id="3050e6f" data-element_type="widget" data-e-type="widget" data-widget_type="code-highlight.default">
				<div class="elementor-widget-container">
							<div class="prismjs-default  ">
			<pre data-line="" class="highlight-height language-bash ">
				<code readonly="true" class="language-bash">
					<xmp>sh "zip -r mylogs.zip mylogs.logarchive/"</xmp>
				</code>
			</pre>
		</div>
						</div>
				</div>
				<div class="elementor-element elementor-element-fe763f9 elementor-widget elementor-widget-text-editor" data-id="fe763f9" data-element_type="widget" data-e-type="widget" data-widget_type="text-editor.default">
				<div class="elementor-widget-container">
									<p>and add a step in the <em><strong>Jenkinsfile</strong></em> pipeline:</p>								</div>
				</div>
				<div class="elementor-element elementor-element-e663105 elementor-widget elementor-widget-code-highlight" data-id="e663105" data-element_type="widget" data-e-type="widget" data-widget_type="code-highlight.default">
				<div class="elementor-widget-container">
							<div class="prismjs-default  ">
			<pre data-line="" class="highlight-height language-bash ">
				<code readonly="true" class="language-bash">
					<xmp>archiveArtifacts(artifacts: 'test_output/mylogs.zip')</xmp>
				</code>
			</pre>
		</div>
						</div>
				</div>
				<div class="elementor-element elementor-element-ab61782 elementor-widget elementor-widget-text-editor" data-id="ab61782" data-element_type="widget" data-e-type="widget" data-widget_type="text-editor.default">
				<div class="elementor-widget-container">
									<h4><span class="Apple-converted-space"> </span>Browsing through logs</h4>								</div>
				</div>
				<div class="elementor-element elementor-element-777309f elementor-widget elementor-widget-text-editor" data-id="777309f" data-element_type="widget" data-e-type="widget" data-widget_type="text-editor.default">
				<div class="elementor-widget-container">
									<p>Now we can open logs using the <em><strong>Console</strong></em> app which is preinstalled on every MacBook and filter our logs by <em><strong>category</strong></em> by typing the test suite name and test case name separated by space, e.g. „<em><strong>RequestTests testSendRequest</strong></em>„ in the upper right corner and see all logs from that test:</p>								</div>
				</div>
				<div class="elementor-element elementor-element-9d0bc98 elementor-widget elementor-widget-image" data-id="9d0bc98" data-element_type="widget" data-e-type="widget" data-widget_type="image.default">
				<div class="elementor-widget-container">
															<img loading="lazy" decoding="async" width="2560" height="1600" src="https://iosdeveloperdiary.com/wp-content/uploads/2022/10/Screenshot-2022-09-05-at-16.09.02.png" class="attachment-full size-full wp-image-252" alt="" srcset="https://iosdeveloperdiary.com/wp-content/uploads/2022/10/Screenshot-2022-09-05-at-16.09.02.png 2560w, https://iosdeveloperdiary.com/wp-content/uploads/2022/10/Screenshot-2022-09-05-at-16.09.02-300x188.png 300w, https://iosdeveloperdiary.com/wp-content/uploads/2022/10/Screenshot-2022-09-05-at-16.09.02-1024x640.png 1024w, https://iosdeveloperdiary.com/wp-content/uploads/2022/10/Screenshot-2022-09-05-at-16.09.02-768x480.png 768w, https://iosdeveloperdiary.com/wp-content/uploads/2022/10/Screenshot-2022-09-05-at-16.09.02-1536x960.png 1536w, https://iosdeveloperdiary.com/wp-content/uploads/2022/10/Screenshot-2022-09-05-at-16.09.02-2048x1280.png 2048w" sizes="(max-width: 2560px) 100vw, 2560px" />															</div>
				</div>
					</div>
		</div>
					</div>
		</section>
				</div>
		]]></content:encoded>
					
					<wfw:commentRss>https://iosdeveloperdiary.com/collecting-logs-from-physical-device-after-ui-and-unit-tests-on-ci-machine-fastlane-jenkins/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>SSL/TLS for dummies</title>
		<link>https://iosdeveloperdiary.com/ssl-tls-for-dummies/</link>
					<comments>https://iosdeveloperdiary.com/ssl-tls-for-dummies/#respond</comments>
		
		<dc:creator><![CDATA[Tomasz]]></dc:creator>
		<pubDate>Fri, 24 Jun 2022 15:34:17 +0000</pubDate>
				<category><![CDATA[Uncategorized]]></category>
		<category><![CDATA[simple SSL TLS]]></category>
		<guid isPermaLink="false">https://iosdeveloperdiary.com/?p=200</guid>

					<description><![CDATA[Why do some people call it SSL (Secure Socket Layer) and others TLS (Transport Layer Security) Nowadays we use those names interchangeably but the truth is SSL is just an [&#8230;]]]></description>
										<content:encoded><![CDATA[		<div data-elementor-type="wp-post" data-elementor-id="200" class="elementor elementor-200" data-elementor-post-type="post">
						<section class="elementor-section elementor-top-section elementor-element elementor-element-cae409b elementor-section-boxed elementor-section-height-default elementor-section-height-default" data-id="cae409b" data-element_type="section" data-e-type="section">
						<div class="elementor-container elementor-column-gap-default">
					<div class="elementor-column elementor-col-100 elementor-top-column elementor-element elementor-element-b232b0e" data-id="b232b0e" data-element_type="column" data-e-type="column">
			<div class="elementor-widget-wrap elementor-element-populated">
						<div class="elementor-element elementor-element-18c1bb4 elementor-widget elementor-widget-text-editor" data-id="18c1bb4" data-element_type="widget" data-e-type="widget" data-widget_type="text-editor.default">
				<div class="elementor-widget-container">
									<p><span style="font-weight: 400;">Why do some people call it SSL (Secure Socket Layer) and others TLS (Transport Layer Security) Nowadays we use those names interchangeably but the truth is SSL is just an older term</span></p><p><span style="font-weight: 400;">TLS is a protocol that ensures:<br /></span><span style="font-weight: 400;">&#8211; only the sender and receiver can read messages,<br /></span><span style="font-weight: 400;">&#8211; sender and receiver can identify each other,<br /></span><span style="font-weight: 400;">&#8211; messages cannot be changed while being transferred.</span></p><p><span style="font-weight: 400;">This article will present a short story of Bob and Alice . This will help us understand why we need TLS and the basics of how it works.</span></p><p><span style="font-weight: 400;">Here are Bob and Alice:</span></p>								</div>
				</div>
				<div class="elementor-element elementor-element-4b9e815 elementor-widget elementor-widget-image" data-id="4b9e815" data-element_type="widget" data-e-type="widget" data-widget_type="image.default">
				<div class="elementor-widget-container">
															<img loading="lazy" decoding="async" width="300" height="278" src="https://iosdeveloperdiary.com/wp-content/uploads/2022/10/Zrzut-ekranu-2022-07-1-o-11.34.24-300x278.png" class="attachment-medium size-medium wp-image-275" alt="" srcset="https://iosdeveloperdiary.com/wp-content/uploads/2022/10/Zrzut-ekranu-2022-07-1-o-11.34.24-300x278.png 300w, https://iosdeveloperdiary.com/wp-content/uploads/2022/10/Zrzut-ekranu-2022-07-1-o-11.34.24.png 324w" sizes="(max-width: 300px) 100vw, 300px" />															</div>
				</div>
				<div class="elementor-element elementor-element-26d90e2 elementor-widget elementor-widget-text-editor" data-id="26d90e2" data-element_type="widget" data-e-type="widget" data-widget_type="text-editor.default">
				<div class="elementor-widget-container">
									<p><span style="font-weight: 400;">They already know that sending plain text messages over the internet can be dangerous because they can be intercepted by other people. Therefore, they want to find the best way to encrypt their messages.</span></p><p><span style="font-weight: 400;">Now, they have a choice as there are two types of encryption they could use &#8211; symmetric and asymmetric.</span></p>								</div>
				</div>
				<div class="elementor-element elementor-element-684756a elementor-widget elementor-widget-text-editor" data-id="684756a" data-element_type="widget" data-e-type="widget" data-widget_type="text-editor.default">
				<div class="elementor-widget-container">
									<p><span style="font-weight: 400;">Symmetric encryption is based on a special word which is used to encrypt and decrypt messages. In other words, there is a secret phrase used to encrypt and decrypt data and this phrase is called a KEY – we will use this term from now on.</span></p><p><span style="font-weight: 400;">When referring to symmetric encryption one most likely means a variant of AES (Advanced Encryption Standard) The newest LTS1.3 supports only 3 encrypting algorithms &#8211; 2 variants of AES (e.g AES128, AES256 where number indicates symmetric key size) and ChaCha20 (do not worry, I have never heard of ChaCha either…)</span></p>								</div>
				</div>
				<div class="elementor-element elementor-element-ee4675c elementor-widget elementor-widget-text-editor" data-id="ee4675c" data-element_type="widget" data-e-type="widget" data-widget_type="text-editor.default">
				<div class="elementor-widget-container">
									<p><span style="font-weight: 400;">Back to our story… Bob decided to try the symmetric approach first. He made up a key and used it to encrypt his messages making them secure and unreadable to anyone who doesn’t know that key.</span></p><p><span style="font-weight: 400;">As a result, he achieved an acceptable level of security but Alice cannot understand any of it, because she’d also need to to know the key that Bob used to encrypt his messages with.</span></p>								</div>
				</div>
				<div class="elementor-element elementor-element-008e384 elementor-widget elementor-widget-image" data-id="008e384" data-element_type="widget" data-e-type="widget" data-widget_type="image.default">
				<div class="elementor-widget-container">
															<img loading="lazy" decoding="async" width="504" height="322" src="https://iosdeveloperdiary.com/wp-content/uploads/2022/10/Zrzut-ekranu-2022-07-1-o-11.34.43.png" class="attachment-large size-large wp-image-279" alt="" srcset="https://iosdeveloperdiary.com/wp-content/uploads/2022/10/Zrzut-ekranu-2022-07-1-o-11.34.43.png 504w, https://iosdeveloperdiary.com/wp-content/uploads/2022/10/Zrzut-ekranu-2022-07-1-o-11.34.43-300x192.png 300w" sizes="(max-width: 504px) 100vw, 504px" />															</div>
				</div>
				<div class="elementor-element elementor-element-67b361b elementor-widget elementor-widget-text-editor" data-id="67b361b" data-element_type="widget" data-e-type="widget" data-widget_type="text-editor.default">
				<div class="elementor-widget-container">
									<p><span style="font-weight: 400;">When Bob realized she couldn&#8217;t understand anything, he decided to share the key with Alice as his initial and unencrypted message.<br /></span><span style="font-weight: 400;">That’s when a new character appeared… Mallory, who managed to capture that message, obtain the key and decrypt all their private messages.</span></p>								</div>
				</div>
				<div class="elementor-element elementor-element-ba98f20 elementor-widget elementor-widget-image" data-id="ba98f20" data-element_type="widget" data-e-type="widget" data-widget_type="image.default">
				<div class="elementor-widget-container">
															<img loading="lazy" decoding="async" width="300" height="295" src="https://iosdeveloperdiary.com/wp-content/uploads/2022/10/Zrzut-ekranu-2022-07-1-o-11.35.03-300x295.png" class="attachment-medium size-medium wp-image-283" alt="" srcset="https://iosdeveloperdiary.com/wp-content/uploads/2022/10/Zrzut-ekranu-2022-07-1-o-11.35.03-300x295.png 300w, https://iosdeveloperdiary.com/wp-content/uploads/2022/10/Zrzut-ekranu-2022-07-1-o-11.35.03.png 350w" sizes="(max-width: 300px) 100vw, 300px" />															</div>
				</div>
				<div class="elementor-element elementor-element-75d974d elementor-widget elementor-widget-text-editor" data-id="75d974d" data-element_type="widget" data-e-type="widget" data-widget_type="text-editor.default">
				<div class="elementor-widget-container">
									<p><span style="font-weight: 400;">Bob had to find a safer way to exchange the symmetric key. That’s when he decided to try the other approach – asymmetric encryption.</span></p>								</div>
				</div>
				<div class="elementor-element elementor-element-78c1e03 elementor-widget elementor-widget-text-editor" data-id="78c1e03" data-element_type="widget" data-e-type="widget" data-widget_type="text-editor.default">
				<div class="elementor-widget-container">
									<p><span style="font-weight: 400;">In case of the asymmetric approach, Bob and Alice both have their own pair of keys: public and private. The public key is meant to be shared with anyone, while the private key should remain known only to its owner.<br /></span><span style="font-weight: 400;">The power of this type of encryption is that messages encrypted with the public key can only be decrypted using the matching private key, while messages encrypted with the private key can only be decrypted with matching public key.</span></p><p><span style="font-weight: 400;">It’s as if you would use one key to open your house’s door, a different one to close it, and the other way around.</span></p>								</div>
				</div>
				<div class="elementor-element elementor-element-34b66a0 elementor-widget elementor-widget-text-editor" data-id="34b66a0" data-element_type="widget" data-e-type="widget" data-widget_type="text-editor.default">
				<div class="elementor-widget-container">
									<p><span style="font-weight: 400;">Even though it looks like you can use public and private keys interchangeably there is a significant difference between the two. Private key is mathematically a private key and cannot be replaced by a public key. You can recover a public key using a private key but not the other way around.</span></p>								</div>
				</div>
				<div class="elementor-element elementor-element-502d7d1 elementor-widget elementor-widget-text-editor" data-id="502d7d1" data-element_type="widget" data-e-type="widget" data-widget_type="text-editor.default">
				<div class="elementor-widget-container">
									<p><span style="font-weight: 400;">Bob created his own key pair, kept the private key for himself, and sent the public key to Alice as a plain text message since it’s safe for anyone to see it.</span><span style="font-weight: 400;"><br /></span><span style="font-weight: 400;">Then, Alice created her own key pair, and shared the public key with Bob.</span></p>								</div>
				</div>
				<div class="elementor-element elementor-element-1121875 elementor-widget elementor-widget-image" data-id="1121875" data-element_type="widget" data-e-type="widget" data-widget_type="image.default">
				<div class="elementor-widget-container">
															<img loading="lazy" decoding="async" width="768" height="298" src="https://iosdeveloperdiary.com/wp-content/uploads/2022/10/Zrzut-ekranu-2022-07-1-o-11.35.17-768x298.png" class="attachment-medium_large size-medium_large wp-image-284" alt="" srcset="https://iosdeveloperdiary.com/wp-content/uploads/2022/10/Zrzut-ekranu-2022-07-1-o-11.35.17-768x298.png 768w, https://iosdeveloperdiary.com/wp-content/uploads/2022/10/Zrzut-ekranu-2022-07-1-o-11.35.17-300x116.png 300w, https://iosdeveloperdiary.com/wp-content/uploads/2022/10/Zrzut-ekranu-2022-07-1-o-11.35.17.png 788w" sizes="(max-width: 768px) 100vw, 768px" />															</div>
				</div>
				<div class="elementor-element elementor-element-0aff4f4 elementor-widget elementor-widget-text-editor" data-id="0aff4f4" data-element_type="widget" data-e-type="widget" data-widget_type="text-editor.default">
				<div class="elementor-widget-container">
									<p><span style="font-weight: 400;">Bob encrypted message containing the key used in symmetric encryption using Alice’s public key and only Alice can decrypt it because only she has the corresponding private key &#8211; we call it a „key exchange”. After that both Alice and Bob knew the secret key and could continue their conversation using symmetric encryption</span></p>								</div>
				</div>
				<div class="elementor-element elementor-element-af76d87 elementor-widget elementor-widget-text-editor" data-id="af76d87" data-element_type="widget" data-e-type="widget" data-widget_type="text-editor.default">
				<div class="elementor-widget-container">
									<p><span style="font-weight: 400;"><strong>Why not always use asymmetric encryption?</strong> <br /></span><span style="font-weight: 400;">Asymmetric encryption is slower and requires larger key size to achieve the same level of security. </span><span style="font-weight: 400;"><br /></span><span style="font-weight: 400;">This method does not include encrypting entire messages or files like movie.mp4. Instead, data is divided into multiple chunks which are encrypted and decrypted individually and later stitched back together. Symmetric encryption is much simpler in this matter.</span></p>								</div>
				</div>
				<div class="elementor-element elementor-element-3d2455e elementor-widget elementor-widget-text-editor" data-id="3d2455e" data-element_type="widget" data-e-type="widget" data-widget_type="text-editor.default">
				<div class="elementor-widget-container">
									<p><span style="font-weight: 400;">This approach to key exchange is called “RSA key exchange” because it is using RSA cryptography. Nowadays, TLS 1.3 does not support RSA key exchange anymore. I’m using RSA throughout the article for simplicity as RSA can do everything: encrypt, decrypt, sign, validate signatures, and key exchange.</span></p><p><span style="font-weight: 400;">The current implementation of TLS requires using DH (Diffie Hellman) key exchange. In fact, it is not really an „exchange” – in this algorithm both sides of communication generate some public and private values, exchange public parts and calculate a key on their own side ending up with the same key for symmetric encryption, better called as „key agreement”.</span></p><p><span style="font-weight: 400;">There are other variants of this algorithm using Elliptic Curves as a mathematical method to end up with the same key on both sides. It is called ECDH (Elliptic curve Diffie Hellman).</span></p><p><span style="font-weight: 400;"><br /></span><span style="font-weight: 400;">As we can see in rfc8446 section-2, there is no support for DH or ECDH but a variant of them with letter E at the end – DHE and ECDHE where E stands for „ephemeral”. DHE and ECDHE variants both require to generate new keys for every new connection, e.g. in case of the RSA key exchange a new key pair is generated whenever there’s need to exchange a symmetric key. Why is it important?</span></p><p><span style="font-weight: 400;">Imagine that Mallory records every encrypted data sent between Bob and Alice. He doesn’t understand any of it now but after 5 years could steal Alice’s private key, and then be able to decrypt all of those key exchanges. This way, he could obtain the symmetric keys that were used and decrypt every single message that was sent in those last 5 years. However, in case of the ephemeral approach none of the private keys used for key exchange are stored, so there is nothing to steal. This guarantees what is called in cryptography „perfect forward secrecy”.</span></p>								</div>
				</div>
				<div class="elementor-element elementor-element-6f7b3b5 elementor-widget elementor-widget-text-editor" data-id="6f7b3b5" data-element_type="widget" data-e-type="widget" data-widget_type="text-editor.default">
				<div class="elementor-widget-container">
									<p><span style="font-weight: 400;">Now, it looks like Bob and Alice achieved their goal of secure communication… </span><span style="font-weight: 400;"><br /></span><span style="font-weight: 400;">… but then Mallory strikes again by intercepting their key exchange communication:</span></p><p><span style="font-weight: 400;">Bob sends his public key to Alice but Mallory captures this message and pretends to be Alice so he sends his own public key back to Bob. They exchanged keys and started their communication. Then, Mallory did the same with Alice. As a result, Bob and Alice both exchanged their keys with Mallory.</span></p>								</div>
				</div>
				<div class="elementor-element elementor-element-b8193a9 elementor-widget elementor-widget-image" data-id="b8193a9" data-element_type="widget" data-e-type="widget" data-widget_type="image.default">
				<div class="elementor-widget-container">
															<img loading="lazy" decoding="async" width="768" height="351" src="https://iosdeveloperdiary.com/wp-content/uploads/2022/10/Zrzut-ekranu-2022-10-26-o-08.32.35-768x351.png" class="attachment-medium_large size-medium_large wp-image-286" alt="" srcset="https://iosdeveloperdiary.com/wp-content/uploads/2022/10/Zrzut-ekranu-2022-10-26-o-08.32.35-768x351.png 768w, https://iosdeveloperdiary.com/wp-content/uploads/2022/10/Zrzut-ekranu-2022-10-26-o-08.32.35-300x137.png 300w, https://iosdeveloperdiary.com/wp-content/uploads/2022/10/Zrzut-ekranu-2022-10-26-o-08.32.35-1024x468.png 1024w, https://iosdeveloperdiary.com/wp-content/uploads/2022/10/Zrzut-ekranu-2022-10-26-o-08.32.35.png 1314w" sizes="(max-width: 768px) 100vw, 768px" />															</div>
				</div>
				<div class="elementor-element elementor-element-9059c54 elementor-widget elementor-widget-text-editor" data-id="9059c54" data-element_type="widget" data-e-type="widget" data-widget_type="text-editor.default">
				<div class="elementor-widget-container">
									<p><span style="font-weight: 400;">Neither Bob nor Alice were aware of Mallory’s interception and started their conversation:</span></p><p><span style="font-weight: 400;">Bob wanted to send a message to Alice saying: „Hey, I have some secrets to tell you”, but it went to Mallory instead, Mallory had the right keys and could decrypt all messages. After that, Malory could do two things:</span></p><ol><li><span style="font-weight: 400;"> Read secret messages using keys exchanged with Bob, then encrypt this message using the key exchanged with Alice and forward it to her. In that case, Bob and Alice can talk for hours while being unaware of the fact that someone is reading their messages.</span></li><li><span style="font-weight: 400;"> Drop Bob’s message and send his own message to Alice while pretending to be Bob.</span></li></ol>								</div>
				</div>
				<div class="elementor-element elementor-element-a3c73a2 elementor-widget elementor-widget-image" data-id="a3c73a2" data-element_type="widget" data-e-type="widget" data-widget_type="image.default">
				<div class="elementor-widget-container">
															<img loading="lazy" decoding="async" width="694" height="380" src="https://iosdeveloperdiary.com/wp-content/uploads/2022/10/Zrzut-ekranu-2022-07-1-o-11.35.49.png" class="attachment-medium_large size-medium_large wp-image-290" alt="" srcset="https://iosdeveloperdiary.com/wp-content/uploads/2022/10/Zrzut-ekranu-2022-07-1-o-11.35.49.png 694w, https://iosdeveloperdiary.com/wp-content/uploads/2022/10/Zrzut-ekranu-2022-07-1-o-11.35.49-300x164.png 300w" sizes="(max-width: 694px) 100vw, 694px" />															</div>
				</div>
				<div class="elementor-element elementor-element-fdd628f elementor-widget elementor-widget-text-editor" data-id="fdd628f" data-element_type="widget" data-e-type="widget" data-widget_type="text-editor.default">
				<div class="elementor-widget-container">
									<p><span style="font-weight: 400;">These types of attacks are called „Man in the middle attack”. In order to prevent that from happening we need a way to identify the person sending a message, like we identify people using ID cards. An ID card contains personal information and a photo, so someone can compare the photo to an actual person and confirm that this ID belongs to him. We trust that the government institution which issued this ID has done their work well.</span></p><p><span style="font-weight: 400;">In the IT world, those ID cards are called Certificates and include (among other things): owner information, a public key, and a signature &#8211; which is really important as it guarantees that the information in this certificate is trustworthy and wasn’t changed.</span></p>								</div>
				</div>
				<div class="elementor-element elementor-element-5ff8333 elementor-widget elementor-widget-text-editor" data-id="5ff8333" data-element_type="widget" data-e-type="widget" data-widget_type="text-editor.default">
				<div class="elementor-widget-container">
									<p><span style="font-weight: 400;">Before going any further, we need to understand two things: </span></p><p><b>What is hashing</b><span style="font-weight: 400;"> &#8211; hashing means calculating a fixed-sized value from other values. For example, we can take a whole 500 pages long book and generate 64 characters long hash value out of the whole text. This hash value looks to us humans like garbage but it’s not. Those 64 characters are unique for those 500 pages of text, changing just one letter will generate a completely different hash value. Hashing algorithms in cryptography are assumed to be one-way which means there is no practical way to recover the original data from the hash value.</span></p><p><span style="font-weight: 400;">In TLS 1.3, the hashing algorithm used is most likely SHA-2 (SHA256, SHA384, or SHA512).<br /></span><span style="font-weight: 400;">For example, a hash value from text <br />„Hey, my name is Munie</span><b>k</b><span style="font-weight: 400;">” = „064d19817d983f5afc7406914e61426c5de79a40a4d6e1ce0f06d87b1d1670eb”</span></p><p><span style="font-weight: 400;">and after changing just one letter to an uppercase: <br />„Hey, my name is Munie</span><b>K</b><span style="font-weight: 400;">” = „2ec314aba71492045babd66b57e312b616031ac77b38e5d0cb3f516006bdf9d5”</span></p><p><b>How basic signing (creating a signature) works</b><span style="font-weight: 400;"> &#8211; Bob wants to send a message to Alice in a way that makes it possible for Alice to confirm it was really sent by Bob. Be aware that signing does not mean encryption. Signing is for verifying the authenticity and integrity of a message.</span></p><p><span style="font-weight: 400;">Bob can send his message using plain text and attach another version of that  same message but encrypted with his private key. Once Alice receives the message, she can use Bob’s public key (assuming that Alice is sure this public key belongs to Bob) to decrypt the encrypted message and compare it with the  plain text version. If they’re the same, it means the message was not changed and it must have been sent by Bob because only Bob had the right private key to encrypt it. Encrypting the whole message and attaching it to the original message seems impractical so instead we encrypt just the hash value of that message and some padding (pkcs v1.5 padding). This approach is called “digest”.</span></p>								</div>
				</div>
				<div class="elementor-element elementor-element-c7841c5 elementor-widget elementor-widget-text-editor" data-id="c7841c5" data-element_type="widget" data-e-type="widget" data-widget_type="text-editor.default">
				<div class="elementor-widget-container">
									<p>We need another character in this story, a character that is known and trusted by Bob and Alice and ideally by everyone else, let’s call him Ted.<br />Ted’s role is to create certificates for other people.</p><p>Bob wanted to have a valid and trusted certificate, so he sent a signed request with his identity information and public key to Ted and asked him to create a certificate, this request is called CSR (certificate signing request). <br />Ted validated that Bob is really Bob and all informations provided in CSR are correct, then used those informations to create a certificate, and then really important &#8211; Ted signed this certificate using his private key.</p><p>Alice after receiving certificate form Bob verified whether it was signed by Ted by calculating hash value of this certificate, and comparing to the signature decrypted with Ted’s public key, beacuse of that Alice is sure that she can trust informations in this certificate including Bob’s public key and safely send messages decrypted by this key because only true Bob can decrypt those messages &#8211; only Bob has the corresponding private key.</p>								</div>
				</div>
				<div class="elementor-element elementor-element-bac6986 elementor-widget elementor-widget-image" data-id="bac6986" data-element_type="widget" data-e-type="widget" data-widget_type="image.default">
				<div class="elementor-widget-container">
															<img loading="lazy" decoding="async" width="738" height="376" src="https://iosdeveloperdiary.com/wp-content/uploads/2022/10/Zrzut-ekranu-2022-07-1-o-11.36.08.png" class="attachment-medium_large size-medium_large wp-image-300" alt="" srcset="https://iosdeveloperdiary.com/wp-content/uploads/2022/10/Zrzut-ekranu-2022-07-1-o-11.36.08.png 738w, https://iosdeveloperdiary.com/wp-content/uploads/2022/10/Zrzut-ekranu-2022-07-1-o-11.36.08-300x153.png 300w" sizes="(max-width: 738px) 100vw, 738px" />															</div>
				</div>
				<div class="elementor-element elementor-element-e4d14b4 elementor-widget elementor-widget-text-editor" data-id="e4d14b4" data-element_type="widget" data-e-type="widget" data-widget_type="text-editor.default">
				<div class="elementor-widget-container">
									<p>The word „trust” is important here &#8211; whole TLS security after all depends on the simple trust that Ted (CA &#8211; Certificate Authority) has done his job right.</p><p>Let’s imagine that Mallory creates a CSR claiming he owns google.com and globally trusted CA (trusted by all modern operating systems) somehow signed it, now Mallory can do man in the middle attack every time Bob or Alice tries to open gmail.com, google.com, youtube.com, etc.</p><p>And… those things happen from time to time in real life and this is one of the few reasons why the internet is not completely secure.</p>								</div>
				</div>
				<div class="elementor-element elementor-element-3622a56 elementor-widget elementor-widget-text-editor" data-id="3622a56" data-element_type="widget" data-e-type="widget" data-widget_type="text-editor.default">
				<div class="elementor-widget-container">
									<p>Bob and Alice finally achieved a ‚good enough’ level of security. Now they want more people to use this method to communicate with each other, everyone in the city creates their own key pairs and certificates signed by Ted. Tens of thousands of people communicate securely using TLS</p><p>but then Mallory breaked into Ted’s house and stole his private key, created thousand of valid and trusted certificates, pretending to be whoever he wants.</p>								</div>
				</div>
				<div class="elementor-element elementor-element-baf63b5 elementor-widget elementor-widget-image" data-id="baf63b5" data-element_type="widget" data-e-type="widget" data-widget_type="image.default">
				<div class="elementor-widget-container">
															<img loading="lazy" decoding="async" width="462" height="384" src="https://iosdeveloperdiary.com/wp-content/uploads/2022/10/Zrzut-ekranu-2022-07-1-o-11.36.23.png" class="attachment-medium_large size-medium_large wp-image-301" alt="" srcset="https://iosdeveloperdiary.com/wp-content/uploads/2022/10/Zrzut-ekranu-2022-07-1-o-11.36.23.png 462w, https://iosdeveloperdiary.com/wp-content/uploads/2022/10/Zrzut-ekranu-2022-07-1-o-11.36.23-300x249.png 300w" sizes="(max-width: 462px) 100vw, 462px" />															</div>
				</div>
				<div class="elementor-element elementor-element-0797ee0 elementor-widget elementor-widget-text-editor" data-id="0797ee0" data-element_type="widget" data-e-type="widget" data-widget_type="text-editor.default">
				<div class="elementor-widget-container">
									<p>People know that every single certificate issued by Ted must not be trusted. They need a new CA but right now they do it in the right way.</p>								</div>
				</div>
				<div class="elementor-element elementor-element-1d0f30c elementor-widget elementor-widget-text-editor" data-id="1d0f30c" data-element_type="widget" data-e-type="widget" data-widget_type="text-editor.default">
				<div class="elementor-widget-container">
									<p>Ted created a new key pair and certificate and signed it using his own private key (that certificate is called self-signed &#8211; there are no other CAs, he is the source of truth, there is no certificate above this certificate and that’s why is it also called a root certificate). </p><p>Then he created a few other certificates and key pairs and signed those with his first, root certificate, those certificates are called intermediate certificates. Private key from the root certificate is kept in a safe and used e.g. only once every 5 years to generate new intermediate certificates.</p><p>Intermediate certificates will be used to sign other people’s certificates, called client certificates. Instead of one private key to sign all of the client’s certificates, Ted uses many private keys from intermediate certificates, and in case one of them will be compromised, only part of certificates from Ted will become unsafe, only those signed by this single certificate. </p><p>This pattern of client certificate signed by an intermediate certificate signed by root certificate is called „certificate chain” or „chain of trust” (can be more than one intermediate certificate in between)</p><p>Now when Bob sends his certificate to Alice she is unable to verify if this is a valid certificate, because Bob’s certificate was signed by one of the intermediate certificates which Alice doesn’t know. Bob needs to send his certificate and every intermediate in between and only then Alice can see that Bob’s certificate was trusted/signed by intermediate certificate and this certificate was trusted/signed by the root certificate which Alice trusts herself, and that’s it!</p><p>This whole process is a simplification of how a TLS handshake looks like, from now you will be able to understand more complex articles <img src="https://s.w.org/images/core/emoji/17.0.2/72x72/1f642.png" alt="🙂" class="wp-smiley" style="height: 1em; max-height: 1em;" /></p>								</div>
				</div>
					</div>
		</div>
					</div>
		</section>
				</div>
		]]></content:encoded>
					
					<wfw:commentRss>https://iosdeveloperdiary.com/ssl-tls-for-dummies/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>Understanding Sendable protocol in Swift 6</title>
		<link>https://iosdeveloperdiary.com/sendable-in-swift-6/</link>
					<comments>https://iosdeveloperdiary.com/sendable-in-swift-6/#respond</comments>
		
		<dc:creator><![CDATA[Tomasz]]></dc:creator>
		<pubDate>Tue, 19 Apr 2022 17:48:12 +0000</pubDate>
				<category><![CDATA[Uncategorized]]></category>
		<category><![CDATA[async/await]]></category>
		<category><![CDATA[iOS]]></category>
		<category><![CDATA[Sendable protocol]]></category>
		<category><![CDATA[Swift]]></category>
		<guid isPermaLink="false">https://iosdeveloperdiary.com/?p=9</guid>

					<description><![CDATA[This article refers to Swift&#8217;s development version Trunk Development Snapshot (March 22, 2022) and uses -warn-concurrency flag in Xcode Build Settings &#8211; Other Swift Flags in order to experience new [&#8230;]]]></description>
										<content:encoded><![CDATA[		<div data-elementor-type="wp-post" data-elementor-id="9" class="elementor elementor-9" data-elementor-post-type="post">
						<section class="elementor-section elementor-top-section elementor-element elementor-element-6a535849 elementor-section-boxed elementor-section-height-default elementor-section-height-default" data-id="6a535849" data-element_type="section" data-e-type="section">
						<div class="elementor-container elementor-column-gap-default">
					<div class="elementor-column elementor-col-100 elementor-top-column elementor-element elementor-element-57cac5b6" data-id="57cac5b6" data-element_type="column" data-e-type="column">
			<div class="elementor-widget-wrap elementor-element-populated">
						<div class="elementor-element elementor-element-e38313a elementor-widget elementor-widget-text-editor" data-id="e38313a" data-element_type="widget" data-e-type="widget" data-widget_type="text-editor.default">
				<div class="elementor-widget-container">
									<p>This article refers to Swift&#8217;s development version <em>Trunk Development Snapshot (March 22, 2022) </em>and uses <code>-warn-concurrency</code> flag in Xcode Build Settings &#8211; Other Swift Flags in order to experience new async/await restrictions as swift 6 has not yet been implemented.</p>								</div>
				</div>
				<div class="elementor-element elementor-element-44d8fb5 elementor-widget elementor-widget-text-editor" data-id="44d8fb5" data-element_type="widget" data-e-type="widget" data-widget_type="text-editor.default">
				<div class="elementor-widget-container">
									<p>Swift concurrency using Async/Await is not only a way to create a readable and clean concurrency mechanism but also a safe one.<br />One of the most common pitfalls of concurrency is when two or more threads try to use the same memory address at the same time, for example, when one thread is reading a value and the other is attempting to edit it – this situation is called data race and most likely ends up as an application crash.</p>
<p>In new async/await every Task and Actor is accessed at most by one thread at a time so there is no longer a possibility for data race inside.</p>								</div>
				</div>
				<section class="elementor-section elementor-inner-section elementor-element elementor-element-542ac69 elementor-section-boxed elementor-section-height-default elementor-section-height-default" data-id="542ac69" data-element_type="section" data-e-type="section">
							<div class="elementor-background-overlay"></div>
							<div class="elementor-container elementor-column-gap-default">
					<div class="elementor-column elementor-col-100 elementor-inner-column elementor-element elementor-element-6a99d3c" data-id="6a99d3c" data-element_type="column" data-e-type="column">
			<div class="elementor-widget-wrap elementor-element-populated">
						<div class="elementor-element elementor-element-4633a6f elementor-widget elementor-widget-text-editor" data-id="4633a6f" data-element_type="widget" data-e-type="widget" data-widget_type="text-editor.default">
				<div class="elementor-widget-container">
									<p>Note &#8211; Even though Task/Actor is accessed by one thread only, there is no guarantee that it will be always the same thread</p>								</div>
				</div>
				<div class="elementor-element elementor-element-0b052a8 elementor-widget elementor-widget-image" data-id="0b052a8" data-element_type="widget" data-e-type="widget" data-widget_type="image.default">
				<div class="elementor-widget-container">
															<img loading="lazy" decoding="async" width="300" height="109" src="https://iosdeveloperdiary.com/wp-content/uploads/2022/04/Zrzut-ekranu-2022-04-20-o-12.39.43-300x109.png" class="attachment-medium size-medium wp-image-21" alt="" srcset="https://iosdeveloperdiary.com/wp-content/uploads/2022/04/Zrzut-ekranu-2022-04-20-o-12.39.43-300x109.png 300w, https://iosdeveloperdiary.com/wp-content/uploads/2022/04/Zrzut-ekranu-2022-04-20-o-12.39.43.png 428w" sizes="(max-width: 300px) 100vw, 300px" />															</div>
				</div>
				<div class="elementor-element elementor-element-21ad484 elementor-widget elementor-widget-text-editor" data-id="21ad484" data-element_type="widget" data-e-type="widget" data-widget_type="text-editor.default">
				<div class="elementor-widget-container">
									<p><em><strong><code data-enlighter-language="generic" class="EnlighterJSRAW">someFunction</code></strong></em> and <em><strong><code data-enlighter-language="generic" class="EnlighterJSRAW">otherFunction</code></strong></em> may be executed using different threads, every await is a potential suspension point where task can give up its thread and got different one to continue its job.</p>								</div>
				</div>
					</div>
		</div>
					</div>
		</section>
				<div class="elementor-element elementor-element-a1d6665 elementor-widget elementor-widget-text-editor" data-id="a1d6665" data-element_type="widget" data-e-type="widget" data-widget_type="text-editor.default">
				<div class="elementor-widget-container">
									<p><!-- /wp:paragraph --></p>
<p><!-- wp:paragraph --></p>
<p>The problem often occurs when we decide to pass some data between Tasks or Actors.</p>
<p><!-- /wp:paragraph --></p>
<p><!-- wp:paragraph --></p>
<p>Swift is trying to solve it by statically checking if code is safe to be accessed concurrently. Thanks to this mechanism, we will be informed about possible data races already during build time as a compiler error that we need to either solve or ensure the compiler that we know what we are doing.</p>
<p><!-- /wp:paragraph --></p>
<p><!-- wp:paragraph --></p>
<p>That’s where Swift comes with a new marker protocol <em><strong><code data-enlighter-language="generic" class="EnlighterJSRAW">Sendable</code></strong></em> and function attribute <code data-enlighter-language="generic" class="EnlighterJSRAW"><em><strong>@Sendable</strong></em></code></p>
<p><code data-enlighter-language="generic" class="EnlighterJSRAW"><em><strong> </strong></em></code></p>								</div>
				</div>
				<div class="elementor-element elementor-element-5052858 elementor-widget elementor-widget-text-editor" data-id="5052858" data-element_type="widget" data-e-type="widget" data-widget_type="text-editor.default">
				<div class="elementor-widget-container">
									<h2 style="text-transform: capitalize;"><strong>Sendable protocol in Swift 6</strong></h2>								</div>
				</div>
				<div class="elementor-element elementor-element-4b7bef7 elementor-widget__width-initial elementor-widget elementor-widget-text-editor" data-id="4b7bef7" data-element_type="widget" data-e-type="widget" data-widget_type="text-editor.default">
				<div class="elementor-widget-container">
									<p>Sendable protocol in Swift indicates that type is safe to be used concurrently within new swift concurrency and The main rule is that <strong>ONLY Sendable types can escape an Actor or Task to another Actor or Task.</strong></p>
<h6><b><i>[Update 2025] &#8211; <span style="font-size: medium;">The rule stated above is still generally correct but has slightly changed with the implementation of &#8216;Region-based isolation&#8217;</span>&#8211; <a href="https://github.com/swiftlang/swift-evolution/blob/main/proposals/0414-region-based-isolation.md" target="_blank" rel="noopener">SE-0414</a></i></b></h6>
<p><strong> </strong></p>
<p>That&#8217;s pretty much it! Let’s see an example:</p>								</div>
				</div>
				<div class="elementor-element elementor-element-eaab80a elementor-widget elementor-widget-code-highlight" data-id="eaab80a" data-element_type="widget" data-e-type="widget" data-widget_type="code-highlight.default">
				<div class="elementor-widget-container">
							<div class="prismjs-default  ">
			<pre data-line="" class="highlight-height language-swift ">
				<code readonly="true" class="language-swift">
					<xmp>class MyClass {
    var name: String = "Muniek"
}

actor MyActor {
    // Non-Sendable type MyClass
    var myClass: MyClass = .init()
    
    func someFunction() async {
        // Function inside an actor can edit its own variables
        // Actor types has own synchronization mechanism ensuring
        // exclusive access to his own properties
        
        // Every Actor property is isolated to an Actor
        // and can be accessed only from inside that actor
        myClass.name = "Bob"
        
        // Based on our rule we cannot pass actor-isolated
        // non-sendable properties to other Task or Actor
        let otherActor = OtherActor()
        
        // Error: Non-sendable type 'MyClass' passed in implicitly
        // asynchronous call to actor-isolated instance method
        // 'otherFunction(myClass:)' cannot cross actor boundary
        await otherActor.otherFunction(myClass: myClass)
    }
}</xmp>
				</code>
			</pre>
		</div>
						</div>
				</div>
				<div class="elementor-element elementor-element-5c5a1c0 elementor-widget elementor-widget-text-editor" data-id="5c5a1c0" data-element_type="widget" data-e-type="widget" data-widget_type="text-editor.default">
				<div class="elementor-widget-container">
									<p>Passing non-sendable types outside an actor or Task is restricted because Tasks can execute their code in parallel with other Tasks. Using non-sendable instances in parallel may end up in an application crash caused by a data race.</p>
<p><!-- /wp:paragraph --></p>
<p><!-- wp:paragraph --></p>
<p>To solve the problem in our example we need to inform the compiler that the value can be safely passed  concurrently, and we can do so by conforming to the Sendable protocol.</p>
<p><!-- /wp:paragraph --></p>
<p><!-- wp:paragraph --></p>
<p>Simple types like integers, strings, tuples, structs, and enums implicitly conform to Sendable because there are value types and are safe to be passed between concurrency domains as long as every one of its members conforms to the Sendable protocol.</p>
<p><!-- /wp:paragraph --></p>
<p><!-- wp:paragraph --></p>
<p>Actors are internally synchronized protecting their mutable states so also they implicitly conform to Sendable.</p>
<p><!-- /wp:paragraph --></p>
<p><!-- wp:paragraph --></p>
<p>Generic types also conform to Sendable when all types inside conform to Sendable.</p>
<p><!-- /wp:paragraph --></p>
<p><!-- wp:paragraph --></p>
<p>We can just change the declaration of <em><strong><code data-enlighter-language="generic" class="EnlighterJSRAW">MyClass</code></strong></em> to be a struct and everything will be okay, because as a struct it will implicitly conform to Sendable.</p>
<p><!-- /wp:paragraph --></p>
<p><!-- wp:paragraph --></p>
<p>The problem appears when dealing with reference types like Classes and Closures.</p>
<p> </p>								</div>
				</div>
				<div class="elementor-element elementor-element-c83df25 elementor-widget elementor-widget-text-editor" data-id="c83df25" data-element_type="widget" data-e-type="widget" data-widget_type="text-editor.default">
				<div class="elementor-widget-container">
									<h2><strong>Sendable in Classes</strong></h2>								</div>
				</div>
				<div class="elementor-element elementor-element-c239293 elementor-widget elementor-widget-text-editor" data-id="c239293" data-element_type="widget" data-e-type="widget" data-widget_type="text-editor.default">
				<div class="elementor-widget-container">
									<p>Classes do not implicitly conform to Sendable, we must explicitly mark them as Sendable and final class, sendable cannot inherit from classes other than NSObject (for Objective-C interoperability).</p>								</div>
				</div>
				<div class="elementor-element elementor-element-e5f1149 elementor-widget elementor-widget-code-highlight" data-id="e5f1149" data-element_type="widget" data-e-type="widget" data-widget_type="code-highlight.default">
				<div class="elementor-widget-container">
							<div class="prismjs-default  ">
			<pre data-line="" class="highlight-height language-swift ">
				<code readonly="true" class="language-swift">
					<xmp>final class MyModel: Sendable { }</xmp>
				</code>
			</pre>
		</div>
						</div>
				</div>
				<div class="elementor-element elementor-element-49ee98c elementor-widget elementor-widget-text-editor" data-id="49ee98c" data-element_type="widget" data-e-type="widget" data-widget_type="text-editor.default">
				<div class="elementor-widget-container">
									<p>As in the case of other types in class all members must be Sendable, we can easily add some immutable properties like so:</p>								</div>
				</div>
				<div class="elementor-element elementor-element-1e8f341 elementor-widget elementor-widget-code-highlight" data-id="1e8f341" data-element_type="widget" data-e-type="widget" data-widget_type="code-highlight.default">
				<div class="elementor-widget-container">
							<div class="prismjs-default  ">
			<pre data-line="" class="highlight-height language-swift ">
				<code readonly="true" class="language-swift">
					<xmp>final class MyModel: Sendable {
    let name: String = "Bob"
}</xmp>
				</code>
			</pre>
		</div>
						</div>
				</div>
				<div class="elementor-element elementor-element-8e786ce elementor-widget elementor-widget-text-editor" data-id="8e786ce" data-element_type="widget" data-e-type="widget" data-widget_type="text-editor.default">
				<div class="elementor-widget-container">
									<p>It is safe to be passed concurrently because there cannot be a data race in immutable values, multiple thread reading at the same time cannot create data race. Let&#8217;s add a variable:</p>								</div>
				</div>
				<div class="elementor-element elementor-element-ceb3be4 elementor-widget elementor-widget-code-highlight" data-id="ceb3be4" data-element_type="widget" data-e-type="widget" data-widget_type="code-highlight.default">
				<div class="elementor-widget-container">
							<div class="prismjs-default  ">
			<pre data-line="" class="highlight-height language-swift ">
				<code readonly="true" class="language-swift">
					<xmp>final class MyModel: Sendable {
    let name: String = "Bob"
    
    // Error: Stored property 'address' of 'Sendable'-conforming
    // class 'MyModel' is mutable
    var address: String = "Krk"
}</xmp>
				</code>
			</pre>
		</div>
						</div>
				</div>
				<div class="elementor-element elementor-element-6cf5155 elementor-widget elementor-widget-text-editor" data-id="6cf5155" data-element_type="widget" data-e-type="widget" data-widget_type="text-editor.default">
				<div class="elementor-widget-container">
									<p>How can we make sure that concurrent access to the variable is safe?<br />We need to add a synchronization mechanism on our own, using locks, queues, etc.<br />Let&#8217;s imagine that we have a type named <em><strong><code data-enlighter-language="generic" class="EnlighterJSRAW">SuperThreadSafeString</code></strong></em> which is thread safe String type:</p>								</div>
				</div>
				<div class="elementor-element elementor-element-21c7606 elementor-widget elementor-widget-code-highlight" data-id="21c7606" data-element_type="widget" data-e-type="widget" data-widget_type="code-highlight.default">
				<div class="elementor-widget-container">
							<div class="prismjs-default  ">
			<pre data-line="" class="highlight-height language-swift ">
				<code readonly="true" class="language-swift">
					<xmp>final class MyModel: Sendable {
    let name: String = "Bob"
    
    // Error: Stored property 'address' of 'Sendable'-conforming
    // class 'MyModel' is mutable
    var address: SuperThreadSafeString = .init()
}</xmp>
				</code>
			</pre>
		</div>
						</div>
				</div>
				<div class="elementor-element elementor-element-2554949 elementor-widget elementor-widget-text-editor" data-id="2554949" data-element_type="widget" data-e-type="widget" data-widget_type="text-editor.default">
				<div class="elementor-widget-container">
									<p>Even now we still got error that address variable is non-Sendable because compiler is unable to check if it is really thread safe, in this case there is only one option left &#8211; to tell the compiler that we know what we are doing by using <code data-enlighter-language="generic" class="EnlighterJSRAW"><em><strong>@unchecked Sednable</strong></em></code>:</p>								</div>
				</div>
				<div class="elementor-element elementor-element-1d20acf elementor-widget elementor-widget-code-highlight" data-id="1d20acf" data-element_type="widget" data-e-type="widget" data-widget_type="code-highlight.default">
				<div class="elementor-widget-container">
							<div class="prismjs-default  ">
			<pre data-line="" class="highlight-height language-swift ">
				<code readonly="true" class="language-swift">
					<xmp>class MyModel: @unchecked Sendable {
    let name: String = "Bob"
    var address: SuperThreadSafeString = .init()
}</xmp>
				</code>
			</pre>
		</div>
						</div>
				</div>
				<div class="elementor-element elementor-element-b053e7c elementor-widget elementor-widget-text-editor" data-id="b053e7c" data-element_type="widget" data-e-type="widget" data-widget_type="text-editor.default">
				<div class="elementor-widget-container">
									<p>Now the compiler is satisfied, it does not care at all about the Sendability, you can forget any restrictions, but all responsibility is in your hands.</p>
<p> </p>								</div>
				</div>
				<div class="elementor-element elementor-element-38a8725 elementor-widget elementor-widget-text-editor" data-id="38a8725" data-element_type="widget" data-e-type="widget" data-widget_type="text-editor.default">
				<div class="elementor-widget-container">
									<h2><strong>@Sendable attribute for functions</strong></h2>								</div>
				</div>
				<div class="elementor-element elementor-element-f26cdeb elementor-widget elementor-widget-text-editor" data-id="f26cdeb" data-element_type="widget" data-e-type="widget" data-widget_type="text-editor.default">
				<div class="elementor-widget-container">
									<p>Functions can also be problematic when passing between concurrency domains, because they can capture other values with them:</p>								</div>
				</div>
				<div class="elementor-element elementor-element-a75c676 elementor-widget elementor-widget-code-highlight" data-id="a75c676" data-element_type="widget" data-e-type="widget" data-widget_type="code-highlight.default">
				<div class="elementor-widget-container">
							<div class="prismjs-default  ">
			<pre data-line="" class="highlight-height language-swift ">
				<code readonly="true" class="language-swift">
					<xmp>class MyClass {
    func doSomething() {
        var name: String = "Muniek"
        
        let function = {
            name = UUID().uuidString
            print(name)
        }
        
        for _ in 0...1000 {
            Task {
                function()
            }
        }
    }
}</xmp>
				</code>
			</pre>
		</div>
						</div>
				</div>
				<div class="elementor-element elementor-element-ce49588 elementor-widget elementor-widget-text-editor" data-id="ce49588" data-element_type="widget" data-e-type="widget" data-widget_type="text-editor.default">
				<div class="elementor-widget-container">
									<p>We passed a function to a 1000 Tasks which can run concurrently to each other causing the application to crash by data race because the function captured String variable <em><strong><code data-enlighter-language="generic" class="EnlighterJSRAW">name</code></strong></em> by reference and all of Tasks are referencing the same memory address.</p>
<p><!-- /wp:paragraph --></p>
<p><!-- wp:paragraph --></p>
<p>Swift requires closure that is passed between Tasks/Actor to be Sendable, there are few rules to make it to conform to Sendable:</p>
<p><!-- /wp:paragraph --></p>
<p><!-- wp:list --></p>
<ul>
<li>Marking as @Sendable, like in case of @escaping</li>
<li>All values captured by closure must be captured by-value</li>
<li>All captured values must be Sendable</li>
</ul>								</div>
				</div>
				<div class="elementor-element elementor-element-16829f8 elementor-widget elementor-widget-text-editor" data-id="16829f8" data-element_type="widget" data-e-type="widget" data-widget_type="text-editor.default">
				<div class="elementor-widget-container">
									<h2><strong>Sendable closures in Actor</strong></h2>								</div>
				</div>
				<div class="elementor-element elementor-element-47a8ab6 elementor-widget elementor-widget-text-editor" data-id="47a8ab6" data-element_type="widget" data-e-type="widget" data-widget_type="text-editor.default">
				<div class="elementor-widget-container">
									<p>The closure created inside an actor can be passed to another actor/task and executed there concurrently to an actor.</p>								</div>
				</div>
				<div class="elementor-element elementor-element-4e5f525 elementor-widget elementor-widget-code-highlight" data-id="4e5f525" data-element_type="widget" data-e-type="widget" data-widget_type="code-highlight.default">
				<div class="elementor-widget-container">
							<div class="prismjs-default  ">
			<pre data-line="" class="highlight-height language-swift ">
				<code readonly="true" class="language-swift">
					<xmp>actor MyActor {
    var actorIsolatedVariable: String = "Bob"
    
    func doSomething() {
        Task.detached {
           // Error: Expression is 'async' but is not marked with 'await'
           self.change(name: "Michael")
        }
                
        change(name: "Tom")
    }
    
    func change(name: String) {
        actorIsolatedVariable = "Michael"
    }
}</xmp>
				</code>
			</pre>
		</div>
						</div>
				</div>
				<div class="elementor-element elementor-element-858f874 elementor-widget elementor-widget-text-editor" data-id="858f874" data-element_type="widget" data-e-type="widget" data-widget_type="text-editor.default">
				<div class="elementor-widget-container">
									<p><em><strong><code data-enlighter-language="generic" class="EnlighterJSRAW">Task.detached</code></strong></em> Closure will run concurrently to the rest of the code allowing simultaneous mutation of <em><strong><code data-enlighter-language="generic" class="EnlighterJSRAW">actorIsolatedVariable</code></strong></em> causing a potential data race.<br />To avoid this problem, Swift comes with a rule that @Sendable closures are NOT isolated, so actor&#8217;s isolated properties cannot be accessed synchronously.</p>
<p><!-- /wp:paragraph --></p>
<p><!-- wp:paragraph --></p>
<p>But there is an exception:<br />Even though closure passed to an Task.init is @Sendable it inherits Actor isolation and can access actor properties synchronously whether there are Sendable or not:</p>								</div>
				</div>
				<div class="elementor-element elementor-element-57ae5bb elementor-widget elementor-widget-code-highlight" data-id="57ae5bb" data-element_type="widget" data-e-type="widget" data-widget_type="code-highlight.default">
				<div class="elementor-widget-container">
							<div class="prismjs-default  ">
			<pre data-line="" class="highlight-height language-swift ">
				<code readonly="true" class="language-swift">
					<xmp>actor MyActor {
    var name = "Muniek"
    
    func myFunction() {
        name = "Michael"
        
        Task {
            name = "Bob"
        }
    }
}</xmp>
				</code>
			</pre>
		</div>
						</div>
				</div>
				<div class="elementor-element elementor-element-9bc60c4 elementor-widget elementor-widget-text-editor" data-id="9bc60c4" data-element_type="widget" data-e-type="widget" data-widget_type="text-editor.default">
				<div class="elementor-widget-container">
									<p>Every actor uses his own instance of SerialExecutor which can execute at most one job at a time, this synchronization protects actor internal mutable states from data race.<br />Non-Sendable types cannot escape concurrency in which it was created so non-sendable closures created inside an Actor must stay inside an actor and execute on Actor’s executor.<br />Closures executing on the actor’s executor are safe to use the actor’s properties synchronously and that&#8217;s why non-sendable closures created inside an Actor are actor-isolated.</p>								</div>
				</div>
				<div class="elementor-element elementor-element-3deb053 elementor-widget elementor-widget-text-editor" data-id="3deb053" data-element_type="widget" data-e-type="widget" data-widget_type="text-editor.default">
				<div class="elementor-widget-container">
									<p>Let&#8217;s see an example of both sendable and non-sendable closures inside an actor:</p>								</div>
				</div>
				<div class="elementor-element elementor-element-bd9a99b elementor-widget elementor-widget-code-highlight" data-id="bd9a99b" data-element_type="widget" data-e-type="widget" data-widget_type="code-highlight.default">
				<div class="elementor-widget-container">
							<div class="prismjs-default  ">
			<pre data-line="" class="highlight-height language-swift ">
				<code readonly="true" class="language-swift">
					<xmp>actor MyActor {
    var actorIsolatedVariable: String = "Bob"
    
    func someFunction(nonSendableClosure: () -> Void) {
        nonSendableClosure()
    }
    
    func otherFunction(sendableClosure: @Sendable () -> Void) {
        sendableClosure()
    }
    
    func doSomethingInside() {
        someFunction(nonSendableClosure: {
            actorIsolatedVariable = "Michael" // Ok
        })
        
        otherFunction(sendableClosure: {
            // Error: Actor-isolated property 'actorIsolatedVariable'
            // can not be mutated from a Sendable closure
            actorIsolatedVariable = "Michael"
        })
    }
}</xmp>
				</code>
			</pre>
		</div>
						</div>
				</div>
				<div class="elementor-element elementor-element-a27c92a elementor-widget elementor-widget-text-editor" data-id="a27c92a" data-element_type="widget" data-e-type="widget" data-widget_type="text-editor.default">
				<div class="elementor-widget-container">
									<p><strong>There is a new Swift proposal <a href="https://github.com/apple/swift-evolution/blob/main/proposals/0338-clarify-execution-non-actor-async.md" target="_blank" rel="noreferrer noopener">SE-0338</a> which is accepted but not yet implemented, so we can only learn this theoretically</strong></p>
<p><!-- /wp:paragraph --></p>
<p><!-- wp:paragraph --></p>
<p><strong>SE-0338 </strong>Specify that actor-isolated async functions <strong>always</strong> execute on actor’s executor and non actor-isolated async functions <strong>never</strong> executes on actor’s executor.</p>
<h6><strong data-start="158" data-end="175">[Update 2025]</strong><span style="font-size: medium;"> This change was implemented, but later reverted in Swift 6.2 — use </span><code data-start="243" data-end="257">@concurrency</code><span style="font-size: medium;"> to hop off the calling actor.</span></h6>
<p><br />Without those restrictions calling some outside async functions from an actor will run this function on an actor executor until suspends or switch to another actor, let see an example:</p>								</div>
				</div>
				<div class="elementor-element elementor-element-c57f642 elementor-widget elementor-widget-code-highlight" data-id="c57f642" data-element_type="widget" data-e-type="widget" data-widget_type="code-highlight.default">
				<div class="elementor-widget-container">
							<div class="prismjs-default  ">
			<pre data-line="" class="highlight-height language-swift ">
				<code readonly="true" class="language-swift">
					<xmp>class MyClass {
    func longOperation() async {
        // Long async operation that do not need actor isolation
    }
}

actor MyActor {
    func doSomething() async {
        // Calling non-actor isolated async function of MyClass, which will execute on actor’s executor
        await myClass.longOperation()
    }
    
    func doSomethingImportant() async {
        // Something really important here, that need actor isolation
    }
}</xmp>
				</code>
			</pre>
		</div>
						</div>
				</div>
				<div class="elementor-element elementor-element-0dfeb99 elementor-widget elementor-widget-text-editor" data-id="0dfeb99" data-element_type="widget" data-e-type="widget" data-widget_type="text-editor.default">
				<div class="elementor-widget-container">
									<p>If <em><strong><code data-enlighter-language="generic" class="EnlighterJSRAW">doSomething</code></strong></em> function would be called first, actor executor will be kept busy during whole <em><strong><code data-enlighter-language="generic" class="EnlighterJSRAW">longOperation</code></strong></em> execution time which can take a few seconds, and during that time actor is unavailable for other actor-isolated functions.</p>
<p><!-- /wp:paragraph --></p>
<p><!-- wp:paragraph --></p>
<p><strong>But of course, there is an exception:</strong></p>								</div>
				</div>
				<div class="elementor-element elementor-element-d2454bf elementor-widget elementor-widget-code-highlight" data-id="d2454bf" data-element_type="widget" data-e-type="widget" data-widget_type="code-highlight.default">
				<div class="elementor-widget-container">
							<div class="prismjs-default  ">
			<pre data-line="" class="highlight-height language-swift ">
				<code readonly="true" class="language-swift">
					<xmp>actor MyActor {
    var data: Data?
    
    func updateData() async {
        return await withCheckedContinuation { continuation in
            Server.fetchData { data in
                self.data = data
                continuation.resume()
            }
        }
    }
}</xmp>
				</code>
			</pre>
		</div>
						</div>
				</div>
				<div class="elementor-element elementor-element-2a47028 elementor-widget elementor-widget-text-editor" data-id="2a47028" data-element_type="widget" data-e-type="widget" data-widget_type="text-editor.default">
				<div class="elementor-widget-container">
									<p><em><strong><code data-enlighter-language="generic" class="EnlighterJSRAW">withCheckedContinuation</code></strong></em> is an non actor-isolated async function so <strong>should</strong> <strong>not</strong> <strong>be</strong> executed on actor executor <strong>but</strong> closure inside is non-sendable so <strong>should</strong> <strong>be</strong> an actor-isolated.<br />Swift engineer told me that they gonna make <em><strong><code data-enlighter-language="generic" class="EnlighterJSRAW">withCheckedContinuation</code></strong></em> an exception to <strong>SE-0338</strong>.</p>								</div>
				</div>
				<div class="elementor-element elementor-element-f47b0d3 elementor-widget elementor-widget-text-editor" data-id="f47b0d3" data-element_type="widget" data-e-type="widget" data-widget_type="text-editor.default">
				<div class="elementor-widget-container">
									<h2><strong>Known bugs</strong></h2>								</div>
				</div>
				<div class="elementor-element elementor-element-bc8b207 elementor-widget elementor-widget-text-editor" data-id="bc8b207" data-element_type="widget" data-e-type="widget" data-widget_type="text-editor.default">
				<div class="elementor-widget-container">
									<p>There is possible way to pass non-sendable actor-isolated variable outside an actor and mutate it synchronously:</p>								</div>
				</div>
				<div class="elementor-element elementor-element-11d0fd6 elementor-widget elementor-widget-code-highlight" data-id="11d0fd6" data-element_type="widget" data-e-type="widget" data-widget_type="code-highlight.default">
				<div class="elementor-widget-container">
							<div class="prismjs-default  ">
			<pre data-line="" class="highlight-height language-swift ">
				<code readonly="true" class="language-swift">
					<xmp>class MyClass {
    var name = "Muniek"
}

actor MyActor {
    // non-sendable actor-isolated variable
    var myClass: MyClass = .init()
    
    func inside_one() async {
        await someFunctionOutside(myclass: myClass)
    }
    
    func changeName() async {
        myClass.name = "Michael"
    }
}

func someFunctionOutside(myclass: MyClass) async {
    // with SE-0338 implemented, this function will switch
    // from actor executor to a generic executor so there wont be any actor isolation
    
    // without SE-0338 function will switch to generic executor after await
    await Task.yield()
    
    // With or without SE-0338 this mutation of actor-isolated variable
    // occurs without any isolation
    myclass.name = "Bob"
}</xmp>
				</code>
			</pre>
		</div>
						</div>
				</div>
					</div>
		</div>
					</div>
		</section>
				<section class="elementor-section elementor-top-section elementor-element elementor-element-eb57d86 elementor-section-boxed elementor-section-height-default elementor-section-height-default" data-id="eb57d86" data-element_type="section" data-e-type="section">
						<div class="elementor-container elementor-column-gap-default">
					<div class="elementor-column elementor-col-100 elementor-top-column elementor-element elementor-element-c432baa" data-id="c432baa" data-element_type="column" data-e-type="column">
			<div class="elementor-widget-wrap elementor-element-populated">
						<div class="elementor-element elementor-element-057d654 elementor-widget elementor-widget-text-editor" data-id="057d654" data-element_type="widget" data-e-type="widget" data-widget_type="text-editor.default">
				<div class="elementor-widget-container">
									<p><em>Special thanks to <a href="https://www.linkedin.com/in/przemekblasiak/" target="_blank" rel="noopener">Przemek Błasiak</a> for help with editing.</em></p>								</div>
				</div>
					</div>
		</div>
					</div>
		</section>
				</div>
		]]></content:encoded>
					
					<wfw:commentRss>https://iosdeveloperdiary.com/sendable-in-swift-6/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
	</channel>
</rss>
