<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0" xmlns:cc="http://cyber.law.harvard.edu/rss/creativeCommonsRssModule.html">
    <channel>
        <title><![CDATA[Stories by Chris Mash on Medium]]></title>
        <description><![CDATA[Stories by Chris Mash on Medium]]></description>
        <link>https://medium.com/@chris-mash?source=rss-ea8ebe82ceec------2</link>
        <image>
            <url>https://cdn-images-1.medium.com/fit/c/150/150/1*AxCIbuSw7BW3feOV_zyR9Q@2x.jpeg</url>
            <title>Stories by Chris Mash on Medium</title>
            <link>https://medium.com/@chris-mash?source=rss-ea8ebe82ceec------2</link>
        </image>
        <generator>Medium</generator>
        <lastBuildDate>Sat, 15 Aug 2026 06:15:54 GMT</lastBuildDate>
        <atom:link href="https://medium.com/@chris-mash/feed" rel="self" type="application/rss+xml"/>
        <webMaster><![CDATA[yourfriends@medium.com]]></webMaster>
        <atom:link href="http://medium.superfeedr.com" rel="hub"/>
        <item>
            <title><![CDATA[Knowing when the battle is lost with XCUITests]]></title>
            <link>https://chris-mash.medium.com/knowing-when-the-battle-is-lost-with-xcuitests-d8ada4d118a5?source=rss-ea8ebe82ceec------2</link>
            <guid isPermaLink="false">https://medium.com/p/d8ada4d118a5</guid>
            <category><![CDATA[xcuitest]]></category>
            <category><![CDATA[ios]]></category>
            <category><![CDATA[xcode]]></category>
            <category><![CDATA[macos]]></category>
            <category><![CDATA[swift]]></category>
            <dc:creator><![CDATA[Chris Mash]]></dc:creator>
            <pubDate>Thu, 08 May 2025 19:52:44 GMT</pubDate>
            <atom:updated>2025-05-08T19:52:44.711Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*uG93x17rkzwCf2Tt" /></figure><p>Let’s say you’ve got a suite of XCUITests that takes 90 minutes to run. And let’s say you run those tests in a CI, such as Bitrise. And let’s say those tests start failing fairly early on in the run, many of them, if not all of them!</p><p>Quite possibly the logs you see in CI aren’t necessarily going to have all the information you need to figure out why the tests are failing. In this case what you need is the <em>.xcresult</em> that will only become available once the tests have completed. And certainly with Bitrise you can’t end the pipeline early, otherwise you’ll never get that <em>.xcresult</em>. But it could be a long wait, up to 90 minutes, or even longer if your tests tend to take longer when they’re timing out.</p><p>If something as terrible as this has happened in your tests there’s likely zero value in running the remaining tests. There’s clearly something fundamentally wrong with this test run that will be apparent from the failures so far and will likely be the same for all remaining tests. So why not just skip all the remaining tests?</p><p>This was the situation I found myself in for the nth time and figured I’d spend some of those wasted minutes looking for a solution.</p><p>I came across <a href="https://developer.apple.com/documentation/xctest/xctestobservation"><em>XCTestObservation</em></a>, a protocol that can be used to be informed of tests going through their lifecycle, such as starting, recording issues and finishing.</p><p>I put together a simple implementation of this and it works nicely!</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/339cd25f2ae385a428e20a60842d6ce9/href">https://medium.com/media/339cd25f2ae385a428e20a60842d6ce9/href</a></iframe><p>You can then put it into use in your XCUITests like so:</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/5b911e39da13c95e8fb0c660d4c97ff1/href">https://medium.com/media/5b911e39da13c95e8fb0c660d4c97ff1/href</a></iframe><p>Initially the recorded failure count will be zero so <em>shouldSkipAllTests</em> will report <em>false</em> and not skip each test being run. If enough tests fail then it will become <em>true</em> and all tests from that point will be skipped, bringing your test run to a much quicker end.</p><p><strong>Some things to consider:</strong></p><ul><li>If your tests are setup to retry when they fail then each failure will add to the failure count, which may or may not be desirable. One way to solve this might be to count unique test failures rather than just adding one on every failure.</li><li>Consider whether the total number of failures is right for your use case. Perhaps you’d rather count the number of failures in a row than just the total number across the whole test run.</li><li>I used a singleton for simplicity, you might prefer/need something a little different</li><li>If your tests run in parallel you’ll need to make sure <em>TestObserver</em> is thread-safe to avoid problems.</li></ul><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=d8ada4d118a5" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Extracting app logs from an .xcresult]]></title>
            <link>https://chris-mash.medium.com/extracting-app-logs-from-an-xcresult-8a848a2db07c?source=rss-ea8ebe82ceec------2</link>
            <guid isPermaLink="false">https://medium.com/p/8a848a2db07c</guid>
            <category><![CDATA[xcresult]]></category>
            <category><![CDATA[xcode]]></category>
            <category><![CDATA[xcuitest]]></category>
            <category><![CDATA[swift]]></category>
            <category><![CDATA[ios]]></category>
            <dc:creator><![CDATA[Chris Mash]]></dc:creator>
            <pubDate>Thu, 25 Apr 2024 19:51:45 GMT</pubDate>
            <atom:updated>2024-04-25T19:51:45.278Z</atom:updated>
            <content:encoded><![CDATA[<h3>Extracting app logs from an .xcresult</h3><figure><img alt="" src="https://cdn-images-1.medium.com/max/1017/1*Pit0_KYK4WNYVRfT2x3yuA.jpeg" /></figure><p>If you’re a dev and you run tests in CI then you’ve probably run into the scenario (many times) where the tests are fine on your machine but on CI they fail.</p><p>And many times you just can’t tell what’s going wrong from the UI test results or the test runner’s logs, you can just tell that <em>something</em> is going wrong under the hood in the app and if you could see the logs of the app the answer would likely be apparent.</p><p>But where are those logs? They’re not available on CI, you just see the test runner’s logs, something like this:</p><pre>2024-04-25 18:50:44.436099+0100 TestAppUITests-Runner[21640:5238984] [Default] Running tests...<br>    t =      nans Interface orientation changed to Portrait<br>Test Suite &#39;TestAppUITests&#39; started at 2024-04-25 18:50:53.439.<br>Test Case &#39;-[TestAppUITests.TestAppUITests testExample]&#39; started.<br>    t =     0.00s Start Test at 2024-04-25 18:50:53.441<br>    t =     1.07s Set Up<br>    t =     1.16s Open com.chrismash.TestApp<br>    t =     1.16s     Launch com.chrismash.TestApp<br>    t =     5.69s         Setting up automation session<br>    t =    10.12s         Wait for com.chrismash.TestApp to idle<br>    t =    13.30s Waiting 5.0s for &quot;Hello, world!&quot; StaticText to exist<br>    t =    14.33s     Checking `Expect predicate `exists == 1` for object &quot;Hello, world!&quot; StaticText`<br>    t =    14.34s         Checking existence of `&quot;Hello, world!&quot; StaticText`<br>    t =    14.71s Tear Down<br>Test Case &#39;-[TestAppUITests.TestAppUITests testExample]&#39; passed (15.088 seconds).<br>Test Suite &#39;TestAppUITests&#39; passed at 2024-04-25 18:51:08.529.<br>  Executed 1 test, with 0 failures (0 unexpected) in 15.088 (15.090) seconds</pre><p>I’d been plagued by this for years and hadn’t found a solution to it. I think fastlane might have options to get at the app logs, but that wasn’t a great option for some of the projects I was working on.</p><p>Then I stumbled on <a href="https://stackoverflow.com/a/77989536/1751266">an answer on StackOverflow</a> that had appeared only a couple of months ago, pointing out that you can use the <em>xcresulttool </em>that ships with Xcode to extract the logs from an <em>xcresult</em> file!</p><p>The process outlined is a bit tedious to do repeatedly but, as henrique pointed out, it’s totally scriptable and I love nothing more than scripting tedious tasks, so I <em>had</em> to give it a go.</p><p>I’ve shared the resulting script here: <a href="https://github.com/ChrisMash/XCResultExtractor">https://github.com/ChrisMash/XCResultExtractor</a>. It’ll output something a little like this:</p><pre>Standard output and standard error from com.chrismash.TestApp with process ID 21774 beginning at 2024-04-25 17:50:58 +0000<br><br>App initialised<br>ContentView initialised<br>2024-04-25 18:51:03.553575+0100 TestApp[21774:5241363] [Default] Received request to exchange capabilities, remote interface capabilities are: &lt;XCTCapabilities: 0x600000004840&gt;: {<br>    &quot;query runtime issue reporting&quot; = 1;<br>    &quot;query runtime issue reporting/automation type mismatch&quot; = 1;<br>}<br>2024-04-25 18:51:03.561337+0100 TestApp[21774:5241363] [Default] Received request to notify when the main run loop is idle<br>2024-04-25 18:51:03.561388+0100 TestApp[21774:5241363] [Default] Idle notifier finished setting up run loop observer<br>2024-04-25 18:51:03.561542+0100 TestApp[21774:5241363] [Default] Received request to notify when animations are idle<br>2024-04-25 18:51:03.561583+0100 TestApp[21774:5241363] [Default] Sending animations idle reply with error: (null)<br>ContentView: @self changed.</pre><p>There’s “noise” in there from the interaction between the test runner and the app (requests for view hierarchies etc.), but it’s definitely better than nothing. You can see the three logs that the test app (included in the repo) outputs:</p><pre>App initialised<br>ContentView initialised<br>ContentView: @self changed.</pre><p>It’s already helped me out a ton already so I’m looking forward to the future chances to make use of it, rather than dreading them!</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=8a848a2db07c" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Swift 6 is coming in September!]]></title>
            <link>https://chris-mash.medium.com/swift-6-is-coming-in-september-e1495dd15dfd?source=rss-ea8ebe82ceec------2</link>
            <guid isPermaLink="false">https://medium.com/p/e1495dd15dfd</guid>
            <category><![CDATA[xcode]]></category>
            <category><![CDATA[macos]]></category>
            <category><![CDATA[swift]]></category>
            <category><![CDATA[ios]]></category>
            <dc:creator><![CDATA[Chris Mash]]></dc:creator>
            <pubDate>Sun, 25 Feb 2024 13:27:09 GMT</pubDate>
            <atom:updated>2024-02-25T13:27:09.635Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*CmoKbgqf9eUoJJVXDs71RA.jpeg" /></figure><p>As I predicted in my last blog, <a href="https://chris-mash.medium.com/preparing-for-swift-6-bab0620d52d0">Preparing for Swift 6</a>, it seems Swift 6 is actually heading for a September release date!</p><p>The Swift forums post on the <a href="https://forums.swift.org/t/swift-6-0-release-process/70220">Swift 6 Release Process</a> has announced that the Swift 6 release branch is being created March 15th. Given Swift 5.10 is going out in Xcode 15.3 in March it tallies up with the release history of Swift that 6.0 will release in September and be included in Xcode 16. Though we’ll have to wait for WWDC for confirmation on that, I’d be very surprised if it happened any differently!</p><p>So maybe it’s time to start enabling all those Swift-6-preparatory feature flags in your projects so the adoption of Swift 6 goes as smoothly as possible! Read more in my last blog: <a href="https://chris-mash.medium.com/preparing-for-swift-6-bab0620d52d0">Preparing for Swift 6</a></p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=e1495dd15dfd" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Preparing for Swift 6]]></title>
            <link>https://chris-mash.medium.com/preparing-for-swift-6-bab0620d52d0?source=rss-ea8ebe82ceec------2</link>
            <guid isPermaLink="false">https://medium.com/p/bab0620d52d0</guid>
            <category><![CDATA[ios]]></category>
            <category><![CDATA[swift]]></category>
            <category><![CDATA[swift-6]]></category>
            <category><![CDATA[xcode]]></category>
            <category><![CDATA[macos]]></category>
            <dc:creator><![CDATA[Chris Mash]]></dc:creator>
            <pubDate>Tue, 23 Jan 2024 18:01:19 GMT</pubDate>
            <atom:updated>2024-01-23T18:01:19.801Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="A poorly generated cartoonish AI image of a 5 and 6 merged into a single numeral, spraying a water on an unsuspecting person holding an umbrella" src="https://cdn-images-1.medium.com/max/1008/1*ihDlg9nzHBSHJkD6DDJBxg.png" /></figure><p>First things first. Let’s address that bizarre image… I used Bing’s AI image creator to try and show a number 6 fighting a number 5, to represent the breaking changes Swift 6 is bringing. But it seems the AI struggled with that and decided to give me this unholy abomination instead, which I feel deserves to be shared as far and wide as possible!</p><h3>When is it coming?</h3><p>Swift 6 will bring numerous breaking changes to iOS, which is something Apple have been preparing for quite some time. They’ve been implementing breaking changes in Swift 5, hidden behind feature flags, which will become the default behaviour in Swift 6.</p><p>It’s been under discussion since at least January 2020 but there’s actually still no announcement on when it will be released.</p><p>The following are some key posts from the Swift forums relating to Swift 6:</p><p>January 2020: <a href="https://forums.swift.org/t/on-the-road-to-swift-6/32862">On the road to Swift 6</a><br>January 2023: <a href="https://forums.swift.org/t/design-priorities-for-the-swift-6-language-mode/62408">Design Priorities for the Swift 6 Language Mode</a><br>November 2023: <a href="https://forums.swift.org/t/progress-toward-the-swift-6-language-mode/68315">Progress toward the Swift 6 language mode</a></p><p>Swift has been consistent with a cadence of March and September for <a href="https://en.wikipedia.org/wiki/Swift_(programming_language)">major/minor releases</a>. September 2023 saw 5.9 released and 5.10 has already been mentioned, which will presumably come along in March 2024.</p><p><em>Perhaps </em>Swift 6 could come along in September 2024? <em>Maybe</em> we’ll see it announced at WWDC, giving us a few months to get fully prepared? Though that’s a wild guess really, more years might roll by before we see it released!</p><h3>What do we need to do?</h3><p>To get your code ready for Swift 6 you can start enabling the various feature flags Apple have provided in Swift 5 and fixing the warnings or errors produced.</p><p>Ensure you enable the feature flags on <em>all</em> targets: framework, app, unit/UI tests etc. And also make sure you clean the targets and build/run them (test targets often don’t actually build until you run them) to get Xcode to report any warnings or errors.</p><p>Inspect and clean up anything it reports and you’ll be in a much better place to adopt Swift 6 when it’s finally released! If possible you should keep the feature flags enabled so that any new code you write before Swift 6 comes along will be written compatible first time!</p><p>If necessary you can check if the <em>-enable-experimental-feature</em> flags are enabled or not in your code with <em>hasFeature</em> (read more <a href="https://github.com/apple/swift-evolution/blob/main/proposals/0362-piecemeal-future-features.md#feature-detection-in-source-code">here</a>). Even when Swift 6 is adopted <em>hasFeature</em> will report <em>true</em> so you don’t have to worry about it thinking the feature flags don’t exist anymore! In some situations this might help to prepare code early if it requires any kind of incompatible change as you can have both old and new code present at the same time.</p><h3>Things we can opt into early</h3><p><a href="https://forums.swift.org/t/progress-toward-the-swift-6-language-mode/68315">Progress toward the Swift 6 language mode</a> calls out various things we can already opt into voluntarily.</p><p>I’ve summarised everything I could find here for you and provided a bit of a summary and high level assessment. Bear in mind that I’ve not fully digested everything I’m linking too and not played around with many of these feature flags so take it all with a pinch of salt!</p><p><strong>SE-0274:</strong> <a href="https://github.com/apple/swift-evolution/blob/main/proposals/0274-magic-file.md#concise-magic-file-names"><strong>Concise magic file names</strong></a></p><p><strong>Summary: </strong><em>#file</em> will evaluate to <em>&lt;module name&gt;/&lt;filename&gt;</em> rather than a full file path. <em>#filePath</em> is introduced if the full file path is still required</p><p><strong>Compiler flag: </strong><em>-enable-experimental-feature ConciseMagicFile</em> <strong>or </strong><em>-Xfrontend -enable-experimental-concise-pound-file</em></p><p>The latter is mentioned as a prototype (not exactly the same as the final intention). It’s unclear whether that applies to the experimental feature flag too or not.</p><p><strong>High level assessment: </strong>Seems unlikely to cause issues for most projects unless there’s anything very specific about any <em>#file</em> usage</p><p><strong>SE-0286: </strong><a href="https://github.com/apple/swift-evolution/blob/main/proposals/0286-forward-scan-trailing-closures.md#forward-scan-matching-for-trailing-closures"><strong>Forward-scan matching for trailing closures</strong></a></p><p><strong>Summary: </strong>Trailing closure matching scans backwards through parameters to find a match but will instead scan forwards, which may cause changes in behaviour if a function has multiple closure parameters (with default values) of the same type and the trailing closure syntax is used.</p><p><strong>Compiler flag: </strong><em>-enable-experimental-feature ForwardTrailingClosures</em></p><p><strong>High level assessment: </strong>Currently not clear what the decision for Swift 6+ is going to be, so hard to assess the impact as there <em>may </em>be none. It may be worth assessing risky usage of trailing closures and updating to be explicit.</p><p><strong>SE-0337: </strong><a href="https://github.com/apple/swift-evolution/blob/main/proposals/0337-support-incremental-migration-to-concurrency-checking.md"><strong>Incremental migration to concurrency checking</strong></a></p><p><strong>Summary: </strong>Swift 5.5 introduced the <em>Sendable</em> protocol to help eliminate data races, though it was not enforced, in 6 it will be</p><p><strong>Build setting: </strong><em>Strict Concurrency Checking</em><strong><br>Compiler flag: </strong><em>-enable-upcoming-feature StrictConcurrency</em> <strong>or </strong><em>-warn-concurrency</em></p><p><strong>High level assessment: </strong>This is one of the biggest impacts. Properly conforming to <em>Sendable</em> isn’t always straight forward and you don’t need to be using async/await for there to be errors! A project I work on had 600+ errors when enabling complete concurrency checking. There’s some useful additional reading on <a href="https://www.avanderlee.com/swift/sendable-protocol-closures/#preparing-your-code-for-swift-6-with-strict-concurrency-checking">SwiftLee</a>.</p><p><strong>SE-0352: </strong><a href="https://github.com/apple/swift-evolution/blob/main/proposals/0352-implicit-open-existentials.md"><strong>Implicitly Opened Existentials</strong></a></p><p><strong>Summary: </strong>Improvements to existentials to make them easier to convert back into generics, removing some compiler errors that could currently be encountered</p><p><strong>Compiler flag: </strong><em>-enable-upcoming-feature ImplicitOpenExistentials</em></p><p><strong>High level assessment: </strong>For the most part seems like it likely won’t have any effect, but it’s possible that a different overloaded function might end up getting picked with the new behaviour</p><p><strong>SE-0354: </strong><a href="https://github.com/apple/swift-evolution/blob/main/proposals/0354-regex-literals.md#regex-literals"><strong>Regex Literals</strong></a></p><p><strong>Summary: </strong>New support for defining regex literals with <em>/…/</em> will be enabled in Swift 6, which could clash with some comment blocks etc.</p><p><strong>Build setting: </strong><em>Enable Bare Slash Regex Literals</em><strong><br>Compiler flag: </strong><em>-enable-upcoming-feature BareSlashRegexLiterals</em></p><p><strong>High level assessment: </strong>Should be simple enough to enable ahead of time and see if anything breaks, modifications should be straight forward</p><p><strong>SE-0383: </strong><a href="https://github.com/apple/swift-evolution/blob/main/proposals/0383-deprecate-uiapplicationmain-and-nsapplicationmain.md"><strong>Deprecate @UIApplicationMain and @NSApplicationMain</strong></a></p><p><strong>Summary: </strong>Use of <em>UIApplicationMain</em> becomes an error in Swift 6 (already meant to be a warning in Swift 5, though it’s not coming up as one for me!)</p><p><strong>Compiler flag: </strong><em>-enable-upcoming-feature DeprecateApplicationMain</em></p><p><strong>High level assessment: </strong>Trivial to replace it with <em>@main</em></p><p><strong>SE-0384: </strong><a href="https://github.com/apple/swift-evolution/blob/main/proposals/0384-importing-forward-declared-objc-interfaces-and-protocols.md#importing-forward-declared-objective-c-interfaces-and-protocols"><strong>Importing Forward Declared Objective-C Interfaces and Protocols</strong></a></p><p><strong>Summary: </strong>Improve usage of ObjC libraries from Swift code around forward declarations</p><p><strong>Compiler flag: </strong><em>-enable-upcoming-feature ImportObjcForwardDeclarations</em></p><p><strong>High level assessment: </strong>Unlikely to be an issue for most, just a benefit. Currently workarounds would be in place to make the ObjC code usable from Swift and these could be removed from Swift 6, potentially speeding up build times a little.</p><p><strong>SE-0401: </strong><a href="https://github.com/apple/swift-evolution/blob/main/proposals/0401-remove-property-wrapper-isolation.md#remove-actor-isolation-inference-caused-by-property-wrappers"><strong>Remove Actor Isolation Inference caused by Property Wrappers</strong></a></p><p><strong>Summary: </strong>Property wrappers currently infer actor isolation, which can be confusing, they won’t in Swift 6</p><p><strong>Compiler flag: </strong><em>-enable-upcoming-feature DisableOutwardActorInference</em></p><p><strong>High level assessment: </strong>Any use of property wrappers might cause a change in actor isolation in related code, which could cause compilation errors that need resolving.</p><p><strong>SE-0409: </strong><a href="https://github.com/apple/swift-evolution/blob/main/proposals/0409-access-level-on-imports.md"><strong>Access-level modifiers on import declarations</strong></a></p><p><strong>Summary: </strong>Ability to keep dependencies internal to a module</p><p><strong>Compiler flag: </strong><em>-enable-experimental-feature AccessLevelOnImport</em> <br><strong>or maybe </strong>-<em>enable-experimental-feature InternalImportsByDefault</em></p><p><strong>High level assessment: </strong>Shouldn’t be too much impact. Imports will be internal by default so there might be places where you need to add some additional imports to fix build errors. You might see a bit of a speed up in build times due to the compiler having to do less work.</p><h3>Potentially testable in Swift 5.10 (March 2024)</h3><p>The following are mentioned on <a href="https://forums.swift.org/t/progress-toward-the-swift-6-language-mode/68315">Progress toward the Swift 6 language mode</a>, and while the wording seems open to interpretation it looks like these feature flags might be getting added in 5.10.</p><p><strong>SE-0411: </strong><a href="https://github.com/apple/swift-evolution/blob/main/proposals/0411-isolated-default-values.md"><strong>Isolated default values</strong></a></p><p><strong>Summary: </strong>Actor isolation rules will be changing for default arguments and stored property values</p><p><strong>Compiler flag: </strong><em>-enable-upcoming-feature IsolatedDefaultValues</em></p><p><strong>High level assessment: </strong>This could potentially introduce some fun errors to handle</p><p><strong>SE-0412: </strong><a href="https://github.com/apple/swift-evolution/blob/main/proposals/0412-strict-concurrency-for-global-variables.md"><strong>Strict concurrency for global variables</strong></a></p><p><strong>Summary: </strong>An improvement to strict concurrency to cover global variables</p><p><strong>Compiler flag: </strong><em>-enable-experimental-feature GlobalConcurrency</em></p><p><strong>High level assessment: </strong>This could potentially introduce some fun errors to handle</p><p><strong>SE-0418: </strong><a href="https://github.com/apple/swift-evolution/blob/main/proposals/0418-inferring-sendable-for-methods.md"><strong>Inferring @Sendable for methods and key path literals</strong></a></p><p><strong>Summary: </strong>A concurrency improvement that will infer whether functions and key path literals are sendable or not (currently you have to do some workarounds)</p><p><strong>Compiler flag: </strong><em>-enable-experimental-feature InferSendableFromCaptures</em></p><p><strong>High level assessment: </strong>Doesn’t sound like it should have any negative impact, could just make adoption of Sendable easier?</p><p><strong>SE-0414: </strong><a href="https://github.com/apple/swift-evolution/blob/main/proposals/0414-region-based-isolation.md"><strong>Region based isolation</strong></a></p><p><strong>Summary: </strong>A concurrency improvement that will allow non-Sendable values to be transferred if the compiler can determine a data race isn’t caused</p><p><strong>Compiler flag: </strong><em>-enable-experimental-feature RegionBasedIsolation</em></p><p><strong>High level assessment: </strong>Sounds like zero impact and would just make Sendable adoption easier</p><p><strong>SE-????: </strong><a href="https://github.com/apple/swift-evolution/blob/3644f682913c8d0b2eafb1945ff81105fbdc7783/proposals/NNNN-improved-control-over-closure-actor-isolation.md"><strong>Improved control over closure actor isolation</strong></a></p><p>This one’s not on the main branch and the linked proposal is in draft, so not sure if it was included on Progress toward the Swift 6 language mode in error or has perhaps been folded into another proposal or just abandoned? (the link to the pitch is also broken)</p><p><strong>Summary: </strong>A concurrency improvement to give the ability to define the actor isolation of a closure</p><p><strong>Compiler flag: </strong>Unknown</p><p><strong>High level assessment: </strong>Though it’s just a draft it seems like there’s nothing to cause issues in there, just a change that would make it easier to introduce concurrency</p><h3>Not expected in Swift 6</h3><p><strong>SE-0335: </strong><a href="https://github.com/apple/swift-evolution/blob/main/proposals/0335-existential-any.md"><strong>Introduce existential any</strong></a></p><p>This was previously going to be enabled by default in Swift 6 but has been deferred to further in the future, according to <a href="https://forums.swift.org/t/progress-toward-the-swift-6-language-mode/68315">Progress toward the Swift 6 language mode</a>.</p><p><strong>Summary: </strong>All existentials will need to be prefixed with <em>any</em>. More info on <a href="https://www.avanderlee.com/swift/existential-any/#enforced-starting-from-swift-6">SwiftLee</a>.</p><p><strong>Compiler flag: </strong><em>-enable-experimental-feature ExistentialAny</em></p><h3>So when should I be doing all this?</h3><p>Swift 6 doesn’t seem like it’s going to provide forwards compatibility, meaning a dependency built with Swift 6 won’t be compatible with a consuming library built with Swift 5. For example if you use a library like Firebase and they make a release built with Swift 6, but you’re still using Swift 5 that’s not going to compile.</p><p>The opposite should be fine though. If you start using Swift 6 then you’ll still be able to use libraries that are built with Swift 5.</p><p>So an instant adoption of Swift 6 isn’t necessary for everyone, most likely. But you may find the need to adopt it somewhat forced upon you by a dependency you use. But that’s only if you need to upgrade to their latest release once they adopt Swift 6, you can continue to use their older Swift 5 releases until you absolutely need that Swift 6 release. Though that may be sooner than you anticipate if there’s some new feature or fix you need from it!</p><p>Regardless of when you decide to adopt Swift 6, anything you can do to reduce the amount of work it would take, ahead of time, is likely sensible in case you find yourself forced into adopting it at short notice.</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=bab0620d52d0" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Writing good unit tests]]></title>
            <link>https://blog.devgenius.io/writing-good-unit-tests-2158be9ee82d?source=rss-ea8ebe82ceec------2</link>
            <guid isPermaLink="false">https://medium.com/p/2158be9ee82d</guid>
            <category><![CDATA[software-development]]></category>
            <category><![CDATA[tdd]]></category>
            <category><![CDATA[test-driven-development]]></category>
            <category><![CDATA[unit-testing]]></category>
            <dc:creator><![CDATA[Chris Mash]]></dc:creator>
            <pubDate>Tue, 17 Oct 2023 15:32:13 GMT</pubDate>
            <atom:updated>2023-10-17T15:43:02.597Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*XtizSuT5TMvXTuMpLTf0Gg.jpeg" /></figure><p>We write tests to prove that our code is correct now and in the future. If we want to do some refactoring some day then we can rely on “good” unit tests continuing to pass to give us confidence we’ve not caused issues. If the tests aren’t “good” then they potentially bring us no actual value.</p><p>Another example of when good unit tests are beneficial is when updating to new tooling. If a new version of iOS, Android or some other dependency of ours comes along and we want to know if our code works correctly on it then only good unit tests will tell us that, bad ones might still pass when the underlying code is completely broken.</p><h3>What do good unit tests look like?</h3><p>Some things that make good unit tests are when they:</p><ul><li>Validate that the subject under test behaves as it’s intended to, in detail:<br>Given different inputs into the unit, do the correct outputs and side effects occur?</li><li>Isolate the subject under test from other units:<br>If unit A is used by unit B and unit B has some great tests that give coverage of unit A you might feel like skipping any testes for unit A. But what if unit B changes in the future and no longer uses unit A? Then you’ve lost all test coverage for unit A.</li><li>Give meaningful coverage:<br>100% code coverage doesn’t mean you have good quality unit tests, it just means that every branch of your code gets executed when you run your tests, not that there’s any validation that any of it is working correctly</li><li>Probably more things that are important too, this isn’t an exhaustive list, feel free to make any of your own suggestions!</li></ul><p>There are test examples that follow that have been written to be as generic and pseudo-codey as possible so they’re clear for developers from any background. Hopefully they make sense, feel free to comment if anything is unclear!</p><h3>Verify expected values</h3><h4>A poor test example:</h4><p>We call a function on the unit being tested and we verify that its delegate gets the expected function called:</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/1d0bd85c680b754cb55cfb1e21ba5988/href">https://medium.com/media/1d0bd85c680b754cb55cfb1e21ba5988/href</a></iframe><p>But we’re just saying we’re happy with it being passed any value imaginable, which is unlikely to be what we really want.</p><p>The test will happily pass when our code is working as expected, but if it <em>doesn’t</em> continue to work as expected (perhaps in the future after a refactor) it will still continue to pass because the parameter has been considered meaningless.</p><h4>An improved test example</h4><p>Let’s verify that the delegate is called with the actual parameter we expect:</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/29cfd1427ce6d218056980624327b655/href">https://medium.com/media/29cfd1427ce6d218056980624327b655/href</a></iframe><p>Sometimes it can be complicated to validate the parameters because they might be complex generated objects that are non-trivial to recreate in the unit test, but it may well be valuable to go to the extra effort.</p><h3>Verify unexpected function calls aren’t made</h3><h4>A poor test example</h4><p>Building on the example from above, if <em>ADelegate</em> has multiple function calls, such as <em>onSuccess</em> and <em>onError</em> functions, it’s worth making sure that only the expected one is called, as otherwise they could both be called if your code is incorrect and the following test would still pass, even though it’s not behaving correctly:</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/2b08d2597531c3eaa1d0efe971372985/href">https://medium.com/media/2b08d2597531c3eaa1d0efe971372985/href</a></iframe><h4>An improved test example</h4><p>The following test would fail if both functions were called, thus catching a bug for us as early as possible.</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/a5d03021597b8305c047774ea0237ad7/href">https://medium.com/media/a5d03021597b8305c047774ea0237ad7/href</a></iframe><h3>Verify expected behaviour</h3><h4>A poor test example</h4><p>The behaviour of a specific unit can vary wildly from another, so the tests will always come down to the specifics of what the unit is intended to do.</p><p>The following could be a good test if the unit is just mean to hold on to the value it’s given, but in most cases that won’t be all it needs to do, it will likely need to do something with that value. It might pass it on to another class while executing its behaviour.</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/fba46e347975c85ae9ec62ceeaa2912e/href">https://medium.com/media/fba46e347975c85ae9ec62ceeaa2912e/href</a></iframe><h4>An improved test example</h4><p>In order to check that the unit is making use of the value as expected, in isolation from other units, you’ll likely need to use dependency injection so that you can mock out other units and just check that they get the right values passed to them</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/3be9fe59fd6fd0acd99a4d8c02e228bb/href">https://medium.com/media/3be9fe59fd6fd0acd99a4d8c02e228bb/href</a></iframe><p>Now we know that the unit takes the value it’s given, reports it back through its own API (might not be necessary to have this API in a lot of cases of course) and passes it on correctly to its dependency.</p><h3>Verify pre-requisites of your test</h3><h4>A poor test example</h4><p>Let’s say we’ve got a class that should create something and store it somewhere, here’s a test that seems to do that pretty well:</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/c5659498bdb9b9df6bd2fac1583cbd68/href">https://medium.com/media/c5659498bdb9b9df6bd2fac1583cbd68/href</a></iframe><p>We create the unit being tested and it’s going to be store the thing for us and we verify that it’s stored afterwards, awesome right?</p><h4>An improved test example</h4><p>What if another test already stored the value we’re checking for and then our class stops storing it? The test will still pass, but shouldn’t! To avoid this happening unexpectedly we could verify that the stored value isn’t there when we start the test as that will then cause a failure if things aren’t as we assume.</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/4affba6e13dc4c1b9f12be36925c1dc3/href">https://medium.com/media/4affba6e13dc4c1b9f12be36925c1dc3/href</a></iframe><p>Even better is clearing the storage before and after every test to make sure it’s empty, though the verification of the stored value not being present is still valuable in case that goes wrong too.</p><h3>How to get good unit tests?</h3><p>It’s not the only way, but Test Driven Development helps you write great tests and makes you think about the tests right from the start, rather than being an after thought.</p><p>TDD seems to have a somewhat bad reputation with some people, but you don’t have to carry out TDD religiously, you can take some learnings from it and realise that writing tests sooner rather than later makes them better and saves time in a lot of cases.</p><h4>What is TDD?</h4><p>If you’re not familiar with TDD then this slide from a presentation at iOSDevUK, maybe as far back as 2015, sums it up succinctly:</p><figure><img alt="A flow diagram for test driven development. Start with a failing test, write just enough code to make it pass, consider any refactoring that could be done then write the next failing test necessary and repeat until done" src="https://cdn-images-1.medium.com/max/1024/1*AGaB_oL1ApWj93yIwL2VzA.jpeg" /><figcaption>TDD in a nut shell</figcaption></figure><p>You start by writing the simplest test you can think of and initially that’s going to fail because you have no actual functionality written (not even the unit that’s to be tested initially!). Then you write <em>just</em> enough code to make it pass, without about the bigger picture and the end goal.</p><p>A good example of this is that if you need write some code to sort a list then you might start by writing a test that checks that a sort function that’s given an empty list will return an empty list.</p><p>Then you write the sort function and merely return an empty list. Empty list in, empty list out, your test passes!</p><p>You’re still a long way from finishing, but you have a meaningful test and it passes. You then look for any opportunities to refactor your code to make it better (without making it do anything extra) and then you repeat the process by writing your next failing test, making it pass and so on, until you’ve got all the functionality necessary written and all the tests that prove it’s ready to go.</p><h4>So we should do TDD?</h4><p>It seems like it’s not for everyone and doing pure TDD can sometimes feel a bit slow and backwards as you’re intentionally writing incorrect code. If you like the approach, go for it, if not maybe you can skip some of the steps, so long as you still write the necessary tests. Instead of writing a sort function that simply returns an empty list maybe you can jump ahead a bit, but do make sure that you write that test to verify empty list in = empty list out etc.</p><h4>Doesn’t TDD just take longer?</h4><p>It’s always super tempting to just dive into writing the working code because you already know what you want it to do and roughly how it looks, but getting to that working code doesn’t mean you’re done, you still need to get those good unit tests written, and how often have we all written a load of working code quickly and then taken much longer to add the unit tests (or maybe given up early because it was taking too long), so maybe it’s not slower to do TDD (if you also want those good UTs)?</p><h4>Trust me bro, I’ll just add the tests at the end!</h4><p>It can be very difficult to consider what unit tests are necessary for a piece of code that’s already been written, especially if it’s quite complex. If you wrote the tests as you wrote the necessary bits of code you’d probably have all the right tests without having to think too much about it at each step.</p><p>Equally, trying to write tests at the end will likely be quite difficult if you’ve not written your code in a testable manner. Maybe you can’t easily validate the behaviour of the unit because it’s all hidden away and strongly typed.</p><p>Dependency injection is a great way of making your code testable, allowing you to mock dependent classes so that UTs can control their behaviour in specific ways or validate values passed to them. Having to go back and modify your code to make it testable can sometimes be quite a big undertaking, with TDD you’d have realised very early on that it was going to be necessary, so would have been quicker to take care of.</p><h4>Ok, I’m sold on the benefits of TDD, what’s next?</h4><p>Practicing some TDD “katas” (because using martial arts terms is super cool) like the sorting example above can give you a great sense of the benefits of TDD that you can then take forward into your general development work and hopefully think about tests earlier in the process.</p><p>The katas are short exercises, maybe 15–30 minutes, describing the requirements for a class that you can test your TDD chops on.</p><p>Here are some links to kata exercises you can try out:</p><ul><li><a href="https://tddmanifesto.com/exercises/">TDD Manifesto katas</a></li><li><a href="https://kata-log.rocks/tdd">Kata-log katas</a></li></ul><p>A quick search for “TDD katas” will find you even more to choose from!</p><h3>Summary</h3><ul><li>Write tests as early as possible to make sure you’re writing code that’s testable, don’t leave them all to the end</li><li>Isolate the subject under test from other units</li><li>Cover all units with their own tests</li><li>Make sure your tests:<br><strong>• </strong>Verify a wide range of different inputs (e.g. nil, empty strings, negative values etc.)<br><strong>•</strong> Verify expected values, function calls and other behaviour<br><strong>• </strong>Verify unexpected function calls aren’t made<br><strong>• </strong>Verify pre-requisites of your test (e.g. side effects aren’t yet valid)</li><li>A high percentage of code coverage may well be a meaningless statistic and we don’t just want to be able to brag about our percentage, we want good unit tests to watch out backs</li><li>If you’re reviewing a pull request, try to look out for bad unit tests!</li></ul><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=2158be9ee82d" width="1" height="1" alt=""><hr><p><a href="https://blog.devgenius.io/writing-good-unit-tests-2158be9ee82d">Writing good unit tests</a> was originally published in <a href="https://blog.devgenius.io">Dev Genius</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Using ProvisioningProfile and Firebase to monitor profile expiries remotely]]></title>
            <link>https://chris-mash.medium.com/using-provisioningprofile-and-firebase-to-monitor-profile-expiries-remotely-7832f475d7b7?source=rss-ea8ebe82ceec------2</link>
            <guid isPermaLink="false">https://medium.com/p/7832f475d7b7</guid>
            <category><![CDATA[provisioning-profile]]></category>
            <category><![CDATA[xcode]]></category>
            <category><![CDATA[ios]]></category>
            <category><![CDATA[swift]]></category>
            <dc:creator><![CDATA[Chris Mash]]></dc:creator>
            <pubDate>Sun, 30 Apr 2023 12:00:26 GMT</pubDate>
            <atom:updated>2023-05-12T05:47:03.250Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/500/1*kDVhTY_vf2GK_Pnw_FNbHg.jpeg" /></figure><p>Previously I <a href="https://medium.com/@chris-mash/knowing-when-your-ios-apps-provisioning-profile-is-going-to-expire-4689d03d0d5">wrote</a> about my Swift Package <a href="https://github.com/ChrisMash/ProvisioningProfile">ProvisioningProfile</a>, which extracts when your (iOS/watchOS/tvOS/macOS) app’s provisioning profile is going to expire.</p><p>If you’ve got a load of your own apps on your device(s) (or other people’s devices) but they’re not on the App Store or TestFlight then you‘ll have experienced the struggle of the provisioning profile expiring and the app not launching, potentially at a crucial time when it was needed and there’s no dev machine nearby to reinstall it!</p><p>I’ve got (too many) personal apps on my iPhone, iPad and also some on my the iPads belonging to my kids, which is quite a lot to consider if you want those apps to always be available, especially with them all expiring at different times throughout the year!</p><h3>The original plan for ProvisioningProfile</h3><p>Originally I created the ProvisioningProfile package as an easy way to show the expiry date in an app and even show alerts or notifications when the expiry date was nearing. That would work ok for most of my regularly used apps on my iPhone, but there are some that are used less regularly and I don’t use my iPad much at all so those apps would expire without me realising (and my kids would probably miss/ignore any notifications on their iPads).</p><p>So I started thinking about what the next option would be and I figured I needed a cloud database to capture this information and allow me to keep an eye on it myself. So that’s what I did next!</p><p>Whenever I see people talking about cloud databases I see iCloud and Firebase as the forerunners. iCloud would be pretty good for this use case as all my apps are for Apple devices, but I’ve heard there can be issues with it and having dabbled with Firebase’s realtime database previously (and found it to be super straightforward for simple stuff like this) I figured I’d stick to what I know!</p><h3>Firebase &amp; ProvisioningProfile (and yet another app)</h3><p>So the basic idea is that you create a single project in Firebase that houses the realtime database and you register all your app bundle IDs to it so that they can update the database.</p><p>I made a simple “profile logging” Swift package that would use the ProvisioningProfile package to extract the expiry time and insert it into the Firebase database, along with some useful information such as the device name, app name and version. If you follow <a href="https://firebase.google.com/docs/database">the Firebase realtime database tutorial</a> it’s fairly straightforward to update it. This is basically what my package does:</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/fa0b13b2e0f34777b7c2ea7db2b28f3c/href">https://medium.com/media/fa0b13b2e0f34777b7c2ea7db2b28f3c/href</a></iframe><p>I then made yet another iOS “tracking” app (but who doesn’t love creating new apps??) to read from the Firebase database and display the information, as well as scheduling notifications for each app expiring, which of course I’ll actually notice and deal with appropriately! And of course this “tracking” app also logs its profile expiry to the database!</p><p>This has proven to be a pretty nice solution for my use case. It’s not too awkward to integrate it into a new app and then it silently keeps the database up to date:</p><ul><li>Setup your new app on the Firebase console (simply by adding the bundle ID to the existing Firebase project, super quick)</li><li>Download the <em>GoogleService-Info.plist</em> from Firebase and add to the app</li><li>Add the “profile logging” Swift Package to the app</li><li>Call the package’s API to log the expiry when the app launches</li></ul><p>No need to add any UI to display the expiry date or to mess around with scheduling notifications, that’s all handled by the “tracking” app separately!</p><p>And here’s a look at the “tracking” app”</p><figure><img alt="A screenshot of the tracking app showing a list of devices and the apps installed on those devices. Each app lists when its provisioning profile is going to expire." src="https://cdn-images-1.medium.com/max/500/1*AINQ3Pq34wriKjL9gKOt4A.png" /></figure><h3>Some things to bear in mind</h3><h4>Potentially missing changes</h4><p>With this solution, if I install a new app on a device (or the profile is updated for an existing app) and I don’t open up the “tracking” app to pull down its expiry date then it’s unaware of that app so it could then miss the expiry and not notify me. It’s not a likely issue for my use case but it could be for some. I think Firebase might be able to send out database update notifications to apps such that it could deal with this scenario though.</p><h4>False alarms</h4><p>If I install one of my apps from the App Store over the top of a dev version, with my current approach, the “tracking app” will still warn me the app is going to expire, even though it won’t. This is because the App Store versions of my apps don’t update the database. Not a huge issue for me to manage but your mileage may vary. One solution could be to keep the database updated from App Store apps too, removing the entry for the app (or flagging it) if there’s no profile found when running the app (though simulators also don’t have profiles available so keep that in mind).</p><h4>Firebase app limits</h4><p>Firebase has a limit of 30 apps per project on free plans, which could be problematic for those with many apps. You can open your wallet (though I’m not sure how much the limit goes up to for paid plans) or you <em>might</em> be able to find a solution that batches up your apps into multiple projects and then get the app to pull down from each project?</p><h4>Firebase already in use?</h4><p>If you’re already using Firebase in your app for something else then I’m not sure whether this will create an issue. You’d have a specific Firebase project configured in your app for the main functionality but would need a different Firebase project to receive the profile expiry details. I imagine there’s <em>probably</em> a way you could setup your app to start with one configuration, log the expiry and then switch to the main configuration, or maybe you could log it to your main Firebase project and then get that to pass it on to the tracking project (some custom server magic, which might not be everyone’s cup of tea!).</p><h4>Firebase security</h4><p>Security of the database could be a concern. In my setup I need the database to be open to modification by anyone so the plethora of apps can make their updates silently. So I imagine an attacker that found my database could update/delete the data fairly easily. I did look into this a bit and Firebase does offer various solutions but I’m not sure any of them really help my situation much. I did limit reading of the database to my own account and integrated Firebase authentication into the “tracking” app, but I didn’t want to require authentication in all my apps as that would affect the UX and integration complexity too much.</p><p>For my use case I only need this in development builds. All my non-App Store builds are debug and the App Store builds are release, so I’ve skipped the logging in release builds and also excluded the <em>GoogleService-Info.plist</em> (which lists everything you need to access the database) from release builds. So at least that keeps the database a bit more secret.</p><h4>A curveball from Apple</h4><p>In iOS 16 Apple changed <em>UIDevice.name</em> to no longer return the user’s chosen name for the device (which defaults to something like “Chris’ iPhone”) but instead a generic name, unless you jumped through some hoops to get approval for accessing the user’s device name. That was a shame because it was very useful for me to differentiate devices, but I totally understand why Apple changed it.</p><p>I looked into whether I’d be able to jump through Apple’s hoops but it didn’t seem like I would so I had to come up with an alternative. If you’ve looked at the gist for the logging code above then you’ll have already seen what I did. I basically swapped out the devices name for a combination of <em>UIDevice.identifierForVendor </em>and the model of the device model (which I get from <a href="https://github.com/InderKumarRathore/DeviceGuru">DeviceGuru</a>). My “tracking” app has the ability to give a recognisable name to a device in the database so I can re-label it to something more meaningful.</p><p>The device model gives me a clue which device it might be (I have a different iPad model to my kids, though they both have the same model) and then I have to use some logic to figure out which vendor ID identifies which similar device based on the apps that have been logged or the time that the logging happened (e.g. I just installed app X on my son’s iPad so I can tell that this vendor ID in the database is for his iPad).</p><p>With my small data set this is manageable, but if you’ve got a lot of different devices you’re deploying to then you might need something a bit better!</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=7832f475d7b7" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Moving views around in SwiftUI]]></title>
            <link>https://blog.devgenius.io/moving-views-around-in-swiftui-271b5bb4fdd8?source=rss-ea8ebe82ceec------2</link>
            <guid isPermaLink="false">https://medium.com/p/271b5bb4fdd8</guid>
            <category><![CDATA[ios]]></category>
            <category><![CDATA[macos]]></category>
            <category><![CDATA[swift]]></category>
            <category><![CDATA[swiftui]]></category>
            <dc:creator><![CDATA[Chris Mash]]></dc:creator>
            <pubDate>Wed, 16 Feb 2022 19:53:51 GMT</pubDate>
            <atom:updated>2022-02-18T08:15:17.291Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="four playing cards" src="https://cdn-images-1.medium.com/max/1024/1*HWv86a0a0zYLf-iYefy9xQ.jpeg" /><figcaption>Let’s play a game!</figcaption></figure><p>In the earlier days of SwiftUI I was putting together a card game (for funsies) and had most of it working quite nicely but couldn’t figure out how to animate the cards from the deck to a player’s hand. iOS 14 was in beta at this point and I found references to its new <em>matchedGeometryEffect </em>modifier, which seemed to be the answer. Unfortunately, I wasn’t in a position to be making use of beta features at that time so the project came to a standstill.</p><p>Fast forward to now and I’ve finally found myself going back to this concept of moving playing cards around in SwiftUI and can now happily make use of <em>matchedGeometryEffect</em>! I struggled for a bit to figure out how to get it working and I didn’t come across any blogs that dealt with the specific issues I was facing (they were all focussed on moving <em>View</em>s around for ‘hero animations’, which is a bit different), so I thought I’d write up my findings in the hope it helps someone else!</p><p>So to summarise the behavior I was after:</p><ul><li>Cards don’t change size as they move around</li><li>When the cards need to move between different hands and/or the main deck of cards they should move smoothly in a realistic manner</li></ul><p>For those eager to get to the complete code solution you can check out the full example project on my GitHub <a href="https://github.com/ChrisMash/SwiftUI-Playing-Cards">here</a>. For those who’d like a walk-through of the process, read on!</p><h3>Step 1: Models</h3><p>First off we need some models for the objects in our card game:</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/5e6f0ea471346c75d88d8553211a4eed/href">https://medium.com/media/5e6f0ea471346c75d88d8553211a4eed/href</a></iframe><p>We’ve got a <em>Card</em> and a <em>Hand</em>, which contains an array of <em>Card</em>s.</p><p><em>Card </em>is <em>Identifiable,</em> as is often required for SwiftUI (so it knows how to handle the introduction or removal of a view that’s different from another view), and <em>Equatable</em> to facilitate finding the card in an array. The only other data the <em>Card</em> has is a number to represent its value (no suits or face cards in this example).</p><p><em>Hand </em>is also <em>Identifiable</em> for the same reasons and it’s an <em>ObservableObject</em> because our <em>View</em>s are going to want to know when cards are added to the hand, or removed. The <em>cards </em>array uses the <em>@Published </em>property<em> </em>wrapper so that it automatically reports changes to <em>View</em>s that are watching for changes.</p><h3>Step 2: Game state</h3><p>Next up let’s create an object to hold the state of the game:</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/bfaa86828ec0072b4a93ca8d83154423/href">https://medium.com/media/bfaa86828ec0072b4a93ca8d83154423/href</a></iframe><p>This simply holds a deck of cards (represented by the <em>Hand</em> model as it does the job we currently need it to) and an array of <em>Hand</em> models representing the players in the game.</p><p>The <em>init </em>sets up the deck with 20 cards, shuffles them, then creates two <em>Hand</em>s with one <em>Card</em> each to start things off.</p><h3>Step 3: A View for a Card</h3><p>Next up let’s create a <em>View</em> to represent a <em>Card</em>:</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/6f745518b048299b3af4f6c66526e3d8/href">https://medium.com/media/6f745518b048299b3af4f6c66526e3d8/href</a></iframe><p>Fairly straightforward for the most part. We’ve got a <em>ZStack</em> with two <em>RoundedRectangle</em>s to represent the card background and border and on top of that, we render the card’s value with a <em>Text</em>.</p><p>We’ve got a <em>namespace</em> property, of type <em>Namespace.ID</em>, being passed into the <em>View</em>. This is a requirement for <em>matchedGeometryEffect</em>, providing the context that the card exists in. In this example, I’ve used the <em>Card</em>’s value as the id for <em>matchedGeometryEffect</em> as that’s unique enough to identify an individual <em>Card</em> as it gets moved between <em>View</em>s.</p><p>Following some other blogs I found, one of the first issues I had was that, while I could get the cards to animate to their new location, there was a fade animation being applied. The card seemed to disappear from its old location instantly and then faded back in as it moved to its new location:</p><figure><img alt="Example of cards moving from the deck to a player’s hand with a fade in the animation" src="https://cdn-images-1.medium.com/max/640/1*Zxx3ST3O-5-Lc_IAmHPnvg.gif" /><figcaption>All looking good apart from the card fading as it moves</figcaption></figure><p>This behavior wasn’t shown in the other blogs I saw, so I’m not sure if this is a difference between iOS 14 and 15 or something subtly different in my code.</p><p>After a lot more digging I stumbled upon a blog that pointed out that this is the default transition style applied to views when they animate (in any scenario, not just with <em>matchedGeometryEffect</em>). I looked into changing the transition to something that didn’t affect the opacity and eventually I found that using a scale transition, set to 1, was the best option I could find for the desired “don’t affect how the <em>View</em> looks, just move it to the new location”.</p><p>Another thing I’d like to call out here is that other blogs I read, for hero animations, said you should place the <em>matchedGeometryEffect</em> modifier before any <em>frame</em> modifiers to get the desired effect. For hero animations, you want to allow for a change in the frame so this makes sense. In my example, the frame is staying the same so it’s not so necessary. In fact, at one point in putting together my example, it <strong>had</strong> to be placed after the frame, otherwise, the animation was all messed up. I can’t actually reproduce that issue now but it could be something you come across so remember that the order of view modifiers often matters! That’s just good advice for all SwiftUI work to be fair!</p><h3>Step 4: Previews and Namespaces</h3><p>I found that I had to get a bit inventive with the <em>PreviewProvider</em> struct for this <em>View</em>, due to the namespace being passed in and the <em>previews</em> property being <em>static</em>:</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/510cd96cae0d8ad5702a1e4010c1bcbb/href">https://medium.com/media/510cd96cae0d8ad5702a1e4010c1bcbb/href</a></iframe><p>Basically we define a <em>View</em> that contains the <em>CardView</em> and can pass in a <em>Namespace.ID</em> and that’s what we return from <em>previews</em>.</p><h3>Step 5: A View for a Hand</h3><p>Next up let’s create a <em>View</em> to represent a <em>Hand</em>:</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/a04603c16a801d8e53102053136c2005/href">https://medium.com/media/a04603c16a801d8e53102053136c2005/href</a></iframe><p>Here we’ll pass in the <em>Hand</em>, <em>Namespace.ID</em> and closure for when a card is tapped. The Hand uses the <em>@ObservedObject</em> property wrapper so that the <em>View</em> responds to changes published by the hand (i.e. adding/removing of cards) and will rebuild itself as necessary.</p><p>We simply have an <em>HStack</em> which renders each <em>Card</em> in the <em>Hand</em> and if any of them are tapped it calls the closure that was passed into the <em>View</em>.</p><h3>Step 6: A View for the deck</h3><p>Next up let’s create a <em>View</em> to represent the main deck of cards:</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/700b6508465f24dbbe3cc223d8cdd64e/href">https://medium.com/media/700b6508465f24dbbe3cc223d8cdd64e/href</a></iframe><p>Very similar to the <em>HandView</em>, but we render only the last two cards in a <em>ZStack</em>, so they’re on top of each other, just like a deck of cards stacked up.</p><h3>Step 7: Putting it all together</h3><p>Finally, let’s put it all together into the main <em>ContentView</em>:</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/9cb4709965c82894d73239ad45fd2c39/href">https://medium.com/media/9cb4709965c82894d73239ad45fd2c39/href</a></iframe><p>The <em>ContentView</em> creates the <em>GameState</em> and holds on to it (depending on your hierarchy you may want to pass this into the view). It also provides the top-level <em>@Namespace</em> context for the <em>matchedGeometryEffect</em> that gets passed down to each <em>CardView</em>.</p><p>This <em>View</em> is pretty straightforward otherwise. There are some brief instructions at the top explaining how you can interact with the cards, followed by the <em>DeckView</em> and a <em>HandView</em> per <em>Hand</em> in <em>GameState</em>. Each <em>HandView</em> also has a ‘+’ <em>Button</em> that allows you to pull a <em>CardView</em> from the <em>DeckView</em> into that <em>HandView</em> and whenever you tap on a <em>CardView</em> in a <em>HandView</em> it moves it back to the <em>DeckView</em>.</p><p>Moving the cards between the deck and a hand is simply done by moving the <em>Card</em> models between the relevant <em>Hand</em> models, within a <em>withAnimation</em> closure so SwiftUI knows we want it to animate. The <em>matchedGeometryEffect </em>and<em> transition </em>modifiers in <em>CardView</em> provide the information to SwiftUI regarding how it should carry out those animations.</p><figure><img alt="Final result of the example code showing cards moving between the deck and a player’s hand" src="https://cdn-images-1.medium.com/max/640/1*xWX5TE1l3Tq9LXRGoVm7VQ.gif" /><figcaption>The final result!</figcaption></figure><p>And that’s it! As mentioned earlier, there’s a full example project available on my GitHub <a href="https://github.com/ChrisMash/SwiftUI-Playing-Cards">here</a>.</p><p>Feel free to leave any comments with feedback or questions!</p><h3>Issues you may still face</h3><h4>Different iOS versions</h4><p><em>matchedGeometryEffect </em>is available from iOS 14, though I’ve only tested my example on iOS 15, so if you’re trying to use it on iOS 14 there could be some differences. The example compiles for iOS 14, but SwiftUI is still pretty much in its infancy so different OS versions can be problematic!</p><h4>Duplicate view errors</h4><p>I had some trouble getting the observing of cards moving between the different <em>Hand</em>s to work properly. Sometimes the animations wouldn’t happen and the console would get an error logged about duplicate IDs appearing for different <em>View</em>s at the same time. So that could be something that you end up running into and can be tricky to figure out how to avoid it.</p><p>The setup I had where it wasn’t working was before I introduced the <em>DeckView </em>and just had the <em>ZStack</em> of it included directly in <em>ContentView</em>. Because that wasn’t able to observe the <em>Hand</em> of the <em>GameState</em>’s deck it meant that SwiftUI would rebuild some of the <em>View</em>s when the cards moved in/out of the deck, but didn&#39;t think the deck itself needed rebuilding. So just try and make sure anything that can change is being observed so SwiftUI knows it needs rebuilding!</p><h4>ScrollView problems</h4><p>Putting the cards in a <em>ScrollView</em> could be desirable for the player’s hand, otherwise it could easily go off the screen, especially on a portrait iPhone. Unfortunately that doesn’t work well in terms of the transition. When the card is moving from the deck into the hand it renders in the <em>ScrollView</em>’s clipped canvas rather than on top so you see it sliding in out of nowhere. Hopefully this is something that will be fixed in a future iOS version!</p><figure><img alt="Example showing how the ScrollView clips the animation when cards move into the ScrollView" src="https://cdn-images-1.medium.com/max/640/1*RBW-w9UiU9-y_zE8aCo2jw.gif" /><figcaption>ScrollView bad!</figcaption></figure><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=271b5bb4fdd8" width="1" height="1" alt=""><hr><p><a href="https://blog.devgenius.io/moving-views-around-in-swiftui-271b5bb4fdd8">Moving views around in SwiftUI</a> was originally published in <a href="https://blog.devgenius.io">Dev Genius</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Goodbye MFMailComposeViewController?]]></title>
            <link>https://chris-mash.medium.com/goodbye-mfmailcomposeviewcontroller-4d9778e8d862?source=rss-ea8ebe82ceec------2</link>
            <guid isPermaLink="false">https://medium.com/p/4d9778e8d862</guid>
            <category><![CDATA[ios]]></category>
            <category><![CDATA[swift]]></category>
            <dc:creator><![CDATA[Chris Mash]]></dc:creator>
            <pubDate>Sat, 11 Dec 2021 17:14:56 GMT</pubDate>
            <atom:updated>2021-12-11T17:14:56.551Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/300/1*0fczNc9m45FMlwG93NliMQ.png" /></figure><p>For many years I’ve used <em>MFMailComposeViewController</em> in my iOS apps to help the user send feedback emails to me. It’s a nice way of keeping the user in my app and just popping up an email composition sheet to let them say whatever they want to say quickly and easily.</p><p>This approach uses the Mail app of iOS, provided by Apple, which would generally be setup with a user’s iCloud email account and any others they’ve setup in the app themselves.</p><p>But it’s entirely possible that a user doesn’t have an email account setup in the Mail app. Maybe they have a preferred app they use like Gmail, Outlook etc. If that’s the case you’d just get an error from <em>MFMailComposeViewController</em> that it wasn’t possible to send an email with it.</p><p>In the past I’d always taken the easy way out and just displayed an alert saying the email couldn’t be created and listed my email address so they could go off to their alternative email app to write their feedback. I would sometimes even copy my email address to the pasteboard so they could easily paste it into their email app rather than having to memorise it.</p><p>Since iOS 14 a user has been able to setup a preferred default email app, which will then be opened for any email related OS functionality, rather than the Mail app. So a better approach is to go back in time and use the old classic <em>mailto: </em>URL and ask iOS to to find the right app to handle it, i.e. the default email app they’ve selected.</p><p>Here’s a code example showing you can do this with a predefined subject and body for the email:</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/b821b28cf1fbd7b7a7672e404d9f1a42/href">https://medium.com/media/b821b28cf1fbd7b7a7672e404d9f1a42/href</a></iframe><p>Simple as that! Your users have less friction to get in touch with you if they’re not using the Mail app so you’re that little bit more likely to get any feedback they want to share with you.</p><p>You can read up more on other options for <em>mailto: </em>URLs <a href="https://www.rapidtables.com/web/html/mailto.html">here</a>.</p><p>With only the <em>mailto: </em>approach you do lose the benefit of keeping the user in your app, so if they want to continue using your app they need to find their way back, which for less experienced users could be confusing of course.</p><p>You <em>could</em> keep using <em>MFMailComposeViewController</em> by default and just fallback to <em>mailto: </em>if the Mail app isn’t setup, though that would ignore the user’s preference of using a different email app, which is could send them into a fit of rage! It unfortunately doesn’t seem like there’s any way to determine whether the user has a default email app that’s not the Mail app setup, based on <a href="https://stackoverflow.com/questions/65396790/retrive-which-is-the-default-mail-app-ios">this Stackoverflow question</a>.</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=4d9778e8d862" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Easy UIAlertController presentation]]></title>
            <link>https://chris-mash.medium.com/easy-uialertcontroller-presentation-40e69a29ea99?source=rss-ea8ebe82ceec------2</link>
            <guid isPermaLink="false">https://medium.com/p/40e69a29ea99</guid>
            <category><![CDATA[swift]]></category>
            <category><![CDATA[uialertcontroller]]></category>
            <category><![CDATA[ios]]></category>
            <category><![CDATA[xcode]]></category>
            <category><![CDATA[tvos]]></category>
            <dc:creator><![CDATA[Chris Mash]]></dc:creator>
            <pubDate>Thu, 12 Aug 2021 20:37:26 GMT</pubDate>
            <atom:updated>2021-08-12T20:37:26.993Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/360/1*48yNxwP2nY0lqdYqycTjBg.png" /></figure><p>Something that can often be troublesome in iOS (or tvOS) development is presenting alerts at random times while other things might be happening in your UI.</p><p>In iOS 8, Apple deprecated <em>UIAlertView</em>, which didn’t require a specific <em>UIViewController</em> to be presented from, as is required in the <em>UIAlertController</em> that replaced it.</p><p>Suddenly app developers needed to specify which <em>UIViewController</em> would be presenting the alert, and with that came the problems of <em>“what if it’s already presenting something”</em> and <em>“what if it’s in the process of presenting/dismissing something”</em>.</p><p>If you try and present an alert (or any other <em>UIViewController</em>) in one of those scenarios it will silently (just an error logged to the console) fail to present, which could leave your app in a broken state or, at the very least, the user is left without some information/choice you intended them to have.</p><p>I came across a partial solution to some of these problems when taking over an existing test app at work, where it would queue up alerts in the case that something was already being presented. It was interesting but it didn’t fully solve the problem so I started looking for a better approach.</p><p>That’s when I came across <a href="https://williamboles.me/alert-queuing-with-windows/">William Boles’ article</a> on queueing and presenting alerts in their own <em>UIWindow</em>. I took what he’d provided, modified and extended it a bit and turned it into a Swift package which you can checkout on GitHub: <a href="https://github.com/ChrisMash/AlertPresenter">AlertPresenter</a>.</p><p>It’s a great way to be able to present alerts without worrying about the exact state your app is currently in. Sometimes that’s fine, other times you might need something more involved, so this might not be the right solution for everyone, but for fairly simple apps or apps that are being used to test a framework/library it should be a great help!</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=40e69a29ea99" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Xcode: Monitoring your public API — Part 2]]></title>
            <link>https://chris-mash.medium.com/xcode-monitoring-your-public-api-part-2-b234ce353d41?source=rss-ea8ebe82ceec------2</link>
            <guid isPermaLink="false">https://medium.com/p/b234ce353d41</guid>
            <category><![CDATA[ios]]></category>
            <category><![CDATA[macos]]></category>
            <category><![CDATA[objective-c]]></category>
            <category><![CDATA[xcode]]></category>
            <category><![CDATA[swift]]></category>
            <dc:creator><![CDATA[Chris Mash]]></dc:creator>
            <pubDate>Thu, 24 Jun 2021 19:53:58 GMT</pubDate>
            <atom:updated>2021-06-24T19:53:58.031Z</atom:updated>
            <content:encoded><![CDATA[<h3>Xcode: Monitoring your public API — Part 2</h3><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*ZL4hLu50sf9zkkpLUQw20A.png" /></figure><p>In <a href="https://chris-mash.medium.com/xcode-monitoring-your-public-api-part-1-b50a1c372cd6">Part 1</a> we looked at how we could generate the public API of our Objective-C/Swift frameworks in the Swift language. But what if we want to see how our public API looks in ObjC? Most people have moved on from ObjC so it may not be such a big concern for many, but some of the devs using your frameworks might still be using it from ObjC, so it may be worth making sure you’re not breaking the public API for them unexpectedly.</p><h3>Objective-C</h3><p>In an ObjC framework the public API is defined by the umbrella header, which includes all the public headers that exist inside the framework. One approach to generating a listing of the public API is to walk through each public header listed there and include everything that’s defined in them.</p><p>I’ve created a script that does exactly this in <a href="https://github.com/ChrisMash/PublicAPIMonitoringExample/blob/main/Scripts/gen_objc_api_from_objc_framework.sh">the GitHub example project</a>, which generates the following output for the ObjC framework:</p><blockquote>FOUNDATION_EXPORT double ObjC_FrameworkVersionNumber;<br>FOUNDATION_EXPORT const unsigned char ObjC_FrameworkVersionString[];<br>typedef NSWindow XPWindow;<br>typedef UIWindow XPWindow;<br><a href="http://twitter.com/interface">@interface</a> OCClass : NSObject<br> - (NSInteger)getInt;<br> - (NSString* _Nonnull)intToStringWith:(NSInteger)integer;<br> - (NSString* _Nullable)tryIntToStringWith:(NSInteger)integer;<br> - (XPWindow* _Nonnull)getWindow;<br> - (void)macFunction;<br> - (void)iOSFunction;<br><a href="http://twitter.com/end">@end</a><br>typedef NS_ENUM(NSUInteger, EnumValue) {<br> kOne,<br> kTwo,<br> kThree<br>};<br>struct OCStruct {<br> enum EnumValue enumValue;<br>};</blockquote><p>That looks pretty good, all the types defined in the code are showing up, even for different platforms (see the inclusion of the <em>macFunction</em> and <em>iOSFunction</em> methods), so you only need to run it for one platform and you get the public API of everything (the script could be modified to only show the output for a single platform if desired).</p><h3>Swift</h3><p>Swift frameworks already have a file that describes the public API in ObjC, the &lt;<em>framework name&gt;-Swift.h </em>file. It’s the file you’d import into your ObjC code if you wanted to make use of your own Swift code within your framework.</p><p>The raw <em>-Swift.h</em> file has quite a lot of irrelevant noise at the top (at least for what we want from the file), so I put together a script in <a href="https://github.com/ChrisMash/PublicAPIMonitoringExample/blob/main/Scripts/gen_swift_api_from_objc_framework.sh">the GitHub example project</a> that would remove that and just leave what we’re really interested in.</p><p>For the Swift framework here’s the output:</p><blockquote>// Generated by Apple Swift version 5.4 (swiftlang-1205.0.26.9 clang-1205.0.19.55)<br>SWIFT_CLASS(“_TtC15Swift_Framework6SClass”)<br><a href="http://twitter.com/interface">@interface</a> SClass : NSObject<br> - (NSInteger)getInt SWIFT_WARN_UNUSED_RESULT;<br> - (NSString * _Nonnull)intToString:(NSInteger)int_ SWIFT_WARN_UNUSED_RESULT;<br> - (NSString * _Nullable)tryIntToString:(NSInteger)int_ SWIFT_WARN_UNUSED_RESULT;<br> - (nonnull instancetype)init OBJC_DESIGNATED_INITIALIZER;<br><a href="http://twitter.com/end">@end</a></blockquote><p>Well, it’s a bit less than we might have expected, but you have to remember that many Swift types and features aren’t available to ObjC, so the Swift enum is left out and even the Swift class would have been left out had it not been correctly marked for exposure to Swift by inheriting from <em>NSObject</em> and tagging each function with <em>@objc</em>.</p><h3>Conclusion</h3><p>Nice, with part 1 and part 2 we can now generate listings of our public API in both ObjC and Swift, for both ObjC and Swift frameworks! Integrate it all into our way of working (pipelines, pull requests etc.) and we’ll never unexpectedly break our public APIs again (maybe)!</p><p><em>Disclaimer: I’m no shellscript expert by any stretch of the imagination so these scripts may make your skin crawl, who knows! Happy to receive feedback!</em></p><p>As with the scripts in part 1, you should keep an eye on how long these scripts take to run. You may well find that the more code you have in your frameworks the longer they take to execute and might noticeably slow down your build time. You may want to run them only in your CI pipelines (or manually if you don’t have CI!).</p><p>As pointed out in the updated version of part 1, the solution I gave to generate the Swift API from an ObjC framework actually only works if your framework is compatible with macOS. So if you blindly import UIKit, for example, it will fail to generate the API. You can put a load of <em>#if</em>s into your code to make it compile, but you then just get the macOS API out, so if you’re actually just supporting iOS then quite possibly a lot of your public API wouldn’t be included. Hopefully in part 3 I can present a better solution! And we still haven’t covered multi-language frameworks yet!</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=b234ce353d41" width="1" height="1" alt="">]]></content:encoded>
        </item>
    </channel>
</rss>