swiftbysundell.com Open in urlscan Pro
2606:4700:20::681a:2ec  Public Scan

Submitted URL: http://swiftbysundell.com/
Effective URL: https://swiftbysundell.com/
Submission: On April 07 via api from GB — Scanned from GB

Form analysis 0 forms found in the DOM

Text Content

Articles, podcasts and news about Swift development, by John Sundell.

 * Articles
 * Basics
 * Podcast
 * Discover
 * About
 * Search

Bitrise: Easily set up fast, rock-solid continuous integration for your project
with Bitrise. Start automatically building, testing, and deploying your app
today.

 * RSS feed
 * Categories


 * SWIFTUI


 * CONCURRENCY


 * GENERICS


 * UNIT TESTING


RECENTLY PUBLISHED

Show compact list


 * PODCAST: “ACCESSIBILITY ON APPLE’S PLATFORMS” WITH SPECIAL GUEST SOMMER
   PANAGE
   
    * accessibility
    * ui development
   
   Published on 21 Mar 2022
   Listen using:  Apple PodcastsOvercastCastroPocket CastsRSS
   
   Sommer Panage returns to the show to discuss Apple’s various accessibility
   APIs and tools, how to incorporate accessibility support into a team’s
   overall development workflow, and what it was like being an engineering
   manager at Apple.
   
   
   SPONSORS
   
    * Emerge Tools: Optimize your app’s startup time, binary size, and overall
      performance using Emerge’s advanced app optimization and monitoring tools.
      Get started at emergetools.com.
    * Bitrise: Rock-solid continuous integration for your Swift project, which
      now offers 50% faster builds and ad-ons for things like automatic
      deployment. Go to bitrise.io/swift to get started for free.
   
   
   LINKS
   
    * VoiceOver
    * Voice Control
    * Dynamic Type
    * PSPDFKit’s blog post about Dynamic Type
    * Defining accessibility labels
    * Accessibility traits
    * WWDC session about custom accessibility actions
    * WWDC session about using AXCustomContent
    * isReduceMotionEnabled
    * prefersCrossFadeTransitions
    * shouldDifferentiateWithoutColor
    * SwiftUI’s accessibilityElement modifier
    * Audio graphs
    * Intro and outro music by Dariusz Dziuk

 * * Read more about ui development
     
     
     LAYOUT ANCHORS
   
   * Another article about ui development
     
     
     STACKING VIEWS IN SWIFTUI
   
   * Continue exploring ui development
     
     
     SWIFTUI MIX AND MATCH


 * ABSTRACT TYPES AND METHODS IN SWIFT
   
    * generics
    * protocols
    * reference types
   
   Published on 15 Mar 2022
   Discover page available: Generics
   
   In object-oriented programming, an abstract type provides a base
   implementation that other types can inherit from in order to gain access to
   some kind of shared, common functionality. What separates abstract types from
   regular ones is that they’re never meant to be used as-is (in fact, some
   programming languages even prevent abstract types from being instantiated
   directly), since their sole purpose is to act as a common parent for a group
   of related types.
   
   For example, let’s say that we wanted to unify the way we load certain types
   of models over the network, by providing a shared API that we’ll be able to
   use to separate concerns, to facilitate dependency injection and mocking, and
   to keep method names consistent throughout our project.
   
   One abstract type-based way to do that would be to use a base class that’ll
   act as that shared, unified interface for all of our model-loading types.
   Since we don’t want that class to ever be used directly, we’ll make it
   trigger a fatalError if its base implementation is ever called by mistake:
   
   class Loadable<Model> {
       func load(from url: URL) async throws -> Model {
           fatalError("load(from:) has not been implemented")
       }
   }
   
   Then, each Loadable subclass will override the above load method in order to
   provide its loading functionality — like this:
   
   class UserLoader: Loadable<User> {
       override func load(from url: URL) async throws -> User {
           ...
       }
   }
   
   If the above sort of pattern looks familiar, it’s probably because it’s
   essentially the exact same sort of polymorphism that we typically use
   protocols for in Swift. That is, when we want to define an interface, a
   contract, that multiple types can conform to through distinct
   implementations.
   
   Protocols do have a significant advantage over abstract classes, though, in
   that the compiler will enforce that all of their requirements are properly
   implemented — meaning we no longer have to rely on runtime errors (such as
   fatalError) to guard against improper use, since there’s no way to
   instantiate a protocol by itself.
   
   So here’s what our Loadable and UserLoader types from before could look like
   if we were to go the protocol-oriented route, rather than using an abstract
   base class:
   
   protocol Loadable {
       associatedtype Model
       func load(from url: URL) async throws -> Model
   }
   
   class UserLoader: Loadable {
       func load(from url: URL) async throws -> User {
           ...
       }
   }
   
   Note how we’re now using an associated type to enable each Loadable
   implementation to decide what exact Model that it wants to load — which gives
   us a nice mix between full type safety and great flexibility.
   
   So, in general, protocols are definitely the preferred way to declare
   abstract types in Swift, but that doesn’t mean that they’re perfect. In fact,
   our protocol-based Loadable implementation currently has two main drawbacks:
   
    * First, since we had to add an associated type to our protocol in order to
      keep our setup generic and type-safe, that means that Loadable can no
      longer be referenced directly.
    * And second, since protocols can’t contain any form of storage, if we
      wanted to add any stored properties that all Loadable implementations
      could make use of, we’d have to re-declare those properties within every
      single one of those concrete implementations.
   
   That property storage aspect is really a huge advantage of our previous,
   abstract class-based setup. So if we were to revert Loadable back to a class,
   then we’d be able to store all objects that our subclasses would need right
   within our base class itself — removing the need to duplicate those
   properties across multiple types:
   
   class Loadable<Model> {
       let networking: Networking
   let cache: Cache<URL, Model>
   
       init(networking: Networking, cache: Cache<URL, Model>) {
           self.networking = networking
           self.cache = cache
       }
   
       func load(from url: URL) async throws -> Model {
           fatalError("load(from:) has not been implemented")
       }
   }
   
   class UserLoader: Loadable<User> {
       override func load(from url: URL) async throws -> User {
           if let cachedUser = cache.value(forKey: url) {
               return cachedUser
           }
   
           let data = try await networking.data(from: url)
           ...
       }
   }
   
   So, what we’re dealing with here is essentially a classic trade-off scenario,
   where both approaches (abstract classes vs protocols) give us a different set
   of pros and cons. But what if we could combine the two to sort of get the
   best of both worlds?
   
   If we think about it, the only real issue with the abstract class-based
   approach is that fatalError that we had to add within the method that each
   subclass is required to implement, so what if we were to use a protocol just
   for that specific method? Then we could still keep our networking and cache
   properties within our base class — like this:
   
   protocol LoadableProtocol {
       associatedtype Model
       func load(from url: URL) async throws -> Model
   }
   
   class LoadableBase<Model> {
       let networking: Networking
   let cache: Cache<URL, Model>
   
       init(networking: Networking, cache: Cache<URL, Model>) {
           self.networking = networking
           self.cache = cache
       }
   }
   
   The main disadvantage of that approach, though, is that all concrete
   implementations will now have to both subclass LoadableBase and declare that
   they conform to our new LoadableProtocol:
   
   class UserLoader: LoadableBase<User>, LoadableProtocol {
       ...
   }
   
   That might not be a huge issue, but it does arguably make our code a bit less
   elegant. The good news, though, is that we can actually solve that issue by
   using a generic type alias. Since Swift’s composition operator, &, supports
   combining a class with a protocol, we can re-introduce our Loadable type as a
   combination between LoadableBase and LoadableProtocol:
   
   typealias Loadable<Model> = LoadableBase<Model> & LoadableProtocol
   
   That way, concrete types (such as UserLoader) can simply declare that they’re
   Loadable-based, and the compiler will ensure that all such types implement
   our protocol’s load method — while still enabling those types to use the
   properties declared within our base class as well:
   
   class UserLoader: Loadable<User> {
       func load(from url: URL) async throws -> User {
           if let cachedUser = cache.value(forKey: url) {
               return cachedUser
           }
   
           let data = try await networking.data(from: url)
           ...
       }
   }
   
   Neat! The only real disadvantage of the above approach is that Loadable still
   can’t be referenced directly, since it’s still partially a generic protocol
   under the hood. That might not actually be an issue, though — and if that
   ever becomes the case, then we could always use techniques such as type
   erasure to get around such problems.
   
   Another slight caveat with our new type alias-based Loadable setup is that
   such combined type aliases cannot be extended, which could become an issue if
   we wanted to provide a few convenience APIs that we don’t want to (or can’t)
   implement directly within our LoadableBase class.
   
   One way to address that issue, though, would be to declare everything that’s
   needed to implement those convenience APIs within our protocol, which would
   then enable us to extend that protocol by itself:
   
   protocol LoadableProtocol {
       associatedtype Model
   
       var networking: Networking { get }
   var cache: Cache<URL, Model> { get }
   
       func load(from url: URL) async throws -> Model
   }
   
   extension LoadableProtocol {
       func loadWithCaching(from url: URL) async throws -> Model {
           if let cachedModel = cache.value(forKey: url) {
               return cachedModel
           }
   
           let model = try await load(from: url)
           cache.insert(model, forKey: url)
           return model
       }
   }
   
   So that’s a few different ways to use abstract types and methods in Swift.
   Subclassing might not currently be as popular as it once was (and remains to
   be within other programming languages), but I still think these sorts of
   techniques are great to have within our overall Swift development toolbox.
   
   If you have any questions, comments, or feedback, then feel free to reach out
   via either Twitter or email.
   
   Thanks for reading!
   
   Support Swift by Sundell by checking out this sponsor:
   
   Bitrise: Easily set up fast, rock-solid continuous integration for your
   project with Bitrise. In just a few minutes, you can set up builds, tests,
   and automatic App Store and beta deployments for your project, all running in
   the cloud on every pull request and commit. Try it for free today.


 * * GENERICS
     
     Learn how to fully utilize Swift’s powerful generics system.
   
   * Read more about protocols
     
     
     ALTERNATIVES TO PROTOCOLS IN SWIFT
     
     Four different ways of defining abstractions in Swift.
   
   * Another article about protocols
     
     
     CREATING CUSTOM SWIFTUI CONTAINER VIEWS
     
     Using a dedicated protocol to make it easy to define new containers.

 * Support Swift by Sundell by checking out this sponsor:
   
   Bitrise: Easily set up fast, rock-solid continuous integration for your
   project with Bitrise. In just a few minutes, you can set up builds, tests,
   and automatic App Store and beta deployments for your project, all running in
   the cloud on every pull request and commit. Try it for free today.


 * JUDO
   
    * Sponsored
   
   Published on 08 Mar 2022
   
   My thanks to Judo for sponsoring Swift by Sundell — both the website and the
   podcast — during this first quarter of the year. Those of you who have been
   following my work for a while might know that I’m a big fan of the concept of
   “server-driven UIs”, where a UI fetches its entire view configuration from a
   remote server, rather than just downloading its data models.
   
   While I don’t recommend building an entire app that way — for certain kinds
   of screens, such as onboarding or payment flows, home screens or feeds, or
   other kinds of dynamic, content-driven views — being able to instantly change
   the way a given view is presented can be incredibly powerful. It can help
   make an app feel much more dynamic and up-to-date, while also letting teams
   iterate much quicker on such an app’s UI.
   
   However, building all of the infrastructure required to actually implement
   fully native, server-driven UIs is often incredibly complicated and
   time-consuming. That’s why, so far, we’ve mostly seen big tech companies
   adopt that kind of UI paradigm — but now, thanks to Judo, any team can easily
   start using server-driven UIs within their apps.
   
   Judo essentially consists of two parts. First, you’ve got a really nice,
   fully native Mac app that lets you build UIs completely visually — think
   Interface Builder or the SwiftUI canvas, but with a lot more power and
   flexibility:
   
   Then, Judo also provides SDKs for both iOS and Android that let you
   dynamically load and configure the experiences you’ve built using that Mac
   app directly within your mobile app.
   
   That means that you get to decide exactly when and where you want to deploy
   your Judo-based views, and those views can then seamlessly interact with the
   rest of your app. Your users won’t even be able to tell the difference
   between the views that you’ve built from scratch and those that are powered
   by Judo — since all views remain completely native.
   
   Once those views are in place, you’re then free to iterate on them however
   you wish, and you can instantly deploy your changes server-side, without
   requiring you to submit a new binary to the App Store.
   
   If this sounds interesting to you, then head over to judo.app/sundell to try
   Judo completely for free, and to help support Swift by Sundell in the
   process.


 * BASICS: EQUALITY
   
    * Basics
    * language features
    * value types
    * reference types
   
   Published on 04 Mar 2022
   
   Checking whether two objects or values are considered equal is definitely one
   of the most commonly performed operations in all of programming. So, in this
   article, let’s take a look at how Swift models the concept of equality, and
   how that model varies between value and reference types.
   
   One the most interesting aspects of Swift’s implementation of equality is
   that it’s all done in a very protocol-oriented way — meaning that any type
   can become equatable by conforming to the Equatable protocol, which can be
   done like this:
   
   struct Article: Equatable {
       static func ==(lhs: Self, rhs: Self) -> Bool {
           lhs.title == rhs.title && lhs.body == rhs.body
       }
   
       var title: String
       var body: String
   }
   
   The way that we conform to Equatable in the above example is by implementing
   an overload of the == operator, which accepts the two values to compare (lhs,
   the left-hand side value, and rhs, the right-hand side value), and it then
   returns a boolean result as to whether those two values should be considered
   equal.
   
   The good news, though, is that we typically don’t have to write those kinds
   of == operator overloads ourselves, since the compiler is able to
   automatically synthesize such implementations whenever a type’s stored
   properties are all Equatable themselves. So in the case of the above Article
   type, we can actually remove our manual equality checking code, and simply
   make that type look like this:
   
   struct Article: Equatable {
       var title: String
       var body: String
   }
   
   The fact that Swift’s equality checks are so protocol-oriented also gives us
   a ton of power when working with generic types. For example, a collection of
   Equatable-conforming values (such as an Array or Set) are automatically
   considered equatable as well — without requiring any additional code on our
   part:
   
   let latestArticles = [
       Article(
           title: "Writing testable code when using SwiftUI",
           body: "..."
       ),
       Article(title: "Combining protocols in Swift", body: "...")
   ]
   
   let basicsArticles = [
       Article(title: "Loops", body: "..."),
       Article(title: "Availability checks", body: "...")
   ]
   
   if latestArticles == basicsArticles {
       ...
   }
   
   The way that those kinds of collection equality checks work is through
   Swift’s conditional conformances feature, which enables a type to conform to
   a specific protocol only when certain conditions are met. For example, here’s
   how Swift’s Array type conforms to Equatable only when the elements that are
   being stored within a given array are also, in turn, Equatable-conforming —
   which is what makes it possible for us to check whether two Article arrays
   are considered equal:
   
   extension Array where Element: Equatable {
       ...
   }
   
   Since none of the above logic is hard-coded into the compiler itself, we can
   also utilize that exact same conditional conformances-based technique if we
   wanted to make our own generic types conditionally equatable as well. For
   example, our code base might include some form of Group type that can be used
   to label a group of related values:
   
   struct Group<Value> {
       var label: String
       var values: [Value]
   }
   
   To make that Group type conform to Equatable when it’s being used to store
   Equatable values, we simply have to write the following empty extension,
   which looks almost identical to the Array extension that we took a look at
   above:
   
   extension Group: Equatable where Value: Equatable {}
   
   With the above in place, we can now check whether two Article-based Group
   values are equal, just like we could when using arrays:
   
   let latestArticles = Group(
       label: "Latest",
       values: [
           Article(
               title: "Writing testable code when using SwiftUI",
               body: "..."
           ),
           Article(title: "Combining protocols in Swift", body: "...")
       ]
   )
   
   let basicsArticles = Group(
       label: "Basics",
       values: [
           Article(title: "Loops", body: "..."),
           Article(title: "Availability checks", body: "...")
       ]
   )
   
   if latestArticles == basicsArticles {
       ...
   }
   
   Just like collections, Swift tuples can also be checked for equality whenever
   their stored values are all Equatable-conforming:
   
   let latestArticles = (
       first: Article(
           title: "Writing testable code when using SwiftUI",
           body: "..."
       ),
       second: Article(title: "Combining protocols in Swift", body: "...")
   )
   
   let basicsArticles = (
       first: Article(title: "Loops", body: "..."),
       second: Article(title: "Availability checks", body: "...")
   )
   
   if latestArticles == basicsArticles {
       ...
   }
   
   However, collections containing the above kind of equatable tuples do not
   automatically conform to Equatable. So, if we were to put the above two
   tuples into two identical arrays, then those wouldn’t be considered
   equatable:
   
   let firstArray = [latestArticles, basicsArticles]
   let secondArray = [latestArticles, basicsArticles]
   
   // Compiler error: Type '(first: Article, second: Article)'
   // cannot conform to 'Equatable':
   if firstArray == secondArray {
       ...
   }
   
   The reason why the above doesn’t work (at least not out of the box) is
   because — like the emitted compiler message alludes to — tuples can’t conform
   to protocols, which means that the Equatable-conforming Array extension that
   we took a look at earlier won’t take effect.
   
   There is a way to make the above work, though, and while I realize that the
   following generic code might not belong in an article labeled as ”Basics”, I
   still thought it would be worth taking a quick look at — since it illustrates
   just how flexible Swift’s equality checks are, and that we’re not just
   limited to implementing a single == overload in order to conform to
   Equatable.
   
   So if we were to add another, custom == overload, specifically for arrays
   that contain equatable two-element tuples, then the above code sample will
   actually compile successfully:
   
   extension Array {
       // This '==' overload will be used specifically when two
       // arrays containing two-element tuples are being compared:
       static func ==<A: Equatable, B: Equatable>(
           lhs: Self,
           rhs: Self
       ) -> Bool where Element == (A, B) {
           // First, we verify that the two arrays that are being
           // compared contain the same amount of elements:
           guard lhs.count == rhs.count else {
               return false
           }
   
           // We then "zip" the two arrays, which will give us
           // a collection where each element contains one element
           // from each array, and we then check that each of those
           // elements pass a standard equality check:
           return zip(lhs, rhs).allSatisfy(==)
       }
   }
   
   Above we can also see how Swift operators can be passed as functions, since
   we’re able to pass == directly to our call to allSatisfy.
   
   So far, we’ve been focusing on how value types (such as structs) behave when
   checked for equality, but what about reference types? For example, let’s say
   that we’ve now decided to turn our previous Article struct into a class
   instead, how would that impact its Equatable implementation?
   
   class Article: Equatable {
       var title: String
       var body: String
       
       init(title: String, body: String) {
           self.title = title
           self.body = body
       }
   }
   
   The first thing that we’ll notice when performing the above change is that
   the compiler is no longer able to automatically synthesize our type’s
   Equatable conformance — since that feature is limited to value types. So if
   we wanted our Article type to remain a class, then we’d have to manually
   implement the == overload that Equatable requires, just like we did at the
   beginning of this article:
   
   class Article: Equatable {
       static func ==(lhs: Article, rhs: Article) -> Bool {
       lhs.title == rhs.title && lhs.body == rhs.body
   }
   
       var title: String
       var body: String
   
       init(title: String, body: String) {
           self.title = title
           self.body = body
       }
   }
   
   However, classes that are subclasses of any kind of Objective-C-based class
   do inherit a default Equatable implementation from NSObject (which is the
   root base class for almost all Objective-C classes). So, if we were to make
   our Article class an NSObject subclass, then it would actually become
   Equatable without strictly requiring us to implement a custom == overload:
   
   class Article: NSObject {
       var title: String
       var body: String
   
       init(title: String, body: String) {
           self.title = title
           self.body = body
           super.init()
       }
   }
   
   While it might be tempting to use the above subclassing technique to avoid
   having to write custom equality checking code, it’s important to point out
   that the only thing that the default Objective-C-provided Equatable
   implementation will do is to check if two classes are the same instance — not
   if they contain the same data. So even though the following two Article
   instances have the same title and body, they won’t be considered equal when
   using the above NSObject-based approach:
   
   let articleA = Article(title: "Title", body: "Body")
   let articleB = Article(title: "Title", body: "Body")
   print(articleA == articleB) // false
   
   Performing those kinds of instance checks can be really useful, though — as
   sometimes we might want to be able to check whether two class-based
   references point to the same underlying instance. We don’t need our classes
   to inherit from NSObject to do that, though, since we can use Swift’s
   built-in triple-equals operator, ===, to perform such a check between any two
   references:
   
   let articleA = Article(title: "Title", body: "Body")
   let articleB = articleA
   print(articleA === articleB) // true
   
   To learn more about the above concept, check out “Identifying objects in
   Swift”.
   
   With that, I believe that we’ve covered all of the basics as to how equality
   works in Swift — for both values and objects, using either custom or
   automatically generated implementations, as well as how generics can be made
   conditionally equatable. If you have any questions, comments, or feedback,
   then feel free to reach out via either Twitter or email.
   
   Thanks for reading!
   
   Support Swift by Sundell by checking out this sponsor:
   
   Bitrise: Easily set up fast, rock-solid continuous integration for your
   project with Bitrise. In just a few minutes, you can set up builds, tests,
   and automatic App Store and beta deployments for your project, all running in
   the cloud on every pull request and commit. Try it for free today.

 * * Read more about Swift’s language features
     
     
     ENUMS WITH CUSTOM RAW TYPES
     
     Defining Swift enums based on completely custom types.
   
   * Another article about Swift’s language features
     
     
     HOW THE RAW VALUES OF INT-BASED ENUMS GET INCREMENTED
     
     And how that can be customized.
   
   * Continue exploring Swift’s language features
     
     
     WHEN CAN SWIFT’S RETURN KEYWORD BE OMITTED?

 * Support Swift by Sundell by checking out this sponsor:
   
   Bitrise: Easily set up fast, rock-solid continuous integration for your
   project with Bitrise. In just a few minutes, you can set up builds, tests,
   and automatic App Store and beta deployments for your project, all running in
   the cloud on every pull request and commit. Try it for free today.


 * PODCAST: “WHERE IS SWIFT HEADED IN 2022?” WITH SPECIAL GUEST JP SIMARD
   
    * what’s new
    * swift evolution
    * standard library
   
   Published on 27 Feb 2022
   Listen using:  Apple PodcastsOvercastCastroPocket CastsRSS
   
   On this 2022 season premiere, JP Simard returns to the show to discuss what’s
   next for Swift in 2022, and what kinds of improvements and new features that
   might be coming to the language during the year.
   
   
   SPONSORS
   
    * Judo: Quickly build native, server-driven UI for iOS and Android, and
      publish instantly, without having to submit updates to the App Store. Try
      it for free today, by going to judo.app/sundell.
    * Bitrise: Rock-solid continuous integration for your Swift project, which
      now offers 50% faster builds and ad-ons for things like automatic
      deployment. Go to bitrise.io/swift to get started for free.
   
   
   LINKS
   
    * JP on Twitter
    * John on Twitter
    * ZenTuner on the App Store
    * The source code for ZenTuner on GitHub
    * Property wrappers
    * Result builders
    * Generics
    * Opaque return types
    * Advent of Code
    * Codable
    * Swift Numerics
    * Swift Argument Parser
    * Swift Concurrency
    * The MainActor attribute
    * Sendable
    * Combine
    * Ted Kremenek’s “On the road to Swift 6” post
    * OpenCombine
    * The open source version of Foundation
    * Rust
    * Swift System
    * Distributed actors
    * Opaque parameter declarations
    * Swift’s new date/time API
    * Swift Markdown
    * Why can’t certain protocols be referenced directly?
    * Type placeholders
    * Adding SwiftUI’s ViewBuilder attribute to functions
    * JP on GitHub
    * JP’s website
    * Intro and outro music by Dariusz Dziuk


 * * THE STANDARD LIBRARY
   
   * Another episode about what’s new
     
     
     39: “SUNDELL BY UNWRAPPED” A HOLIDAY SPECIAL FEATURING JP SIMARD AND JESSE
     SQUIRES
   
   * Read more about the standard library
     
     
     SLICING SWIFT COLLECTIONS
     
     Efficient ways of working with subsets of various collections using the
     standard library’s slicing APIs.


 * WRITING TESTABLE CODE WHEN USING SWIFTUI
   
    * swiftui
    * unit testing
   
   Published on 17 Feb 2022
   Discover page available: SwiftUI
   
   A major part of the challenge of architecting UI-focused code bases tends to
   come down to deciding where to draw the line between the code that needs to
   interact with the platform’s various UI frameworks, versus code that’s
   completely within our own app’s domain of logic.
   
   That task might become especially tricky when working with SwiftUI, as so
   much of our UI-centric logic tends to wind up within our various View
   declarations, which in turn often makes such code really difficult to verify
   using unit tests.
   
   So, in this article, let’s take a look at how we could deal with that
   problem, and explore how to make UI-related logic fully testable — even when
   that logic is primarily used within SwiftUI-based views.
   
   Bitrise: Easily set up fast, rock-solid continuous integration for your
   project with Bitrise. In just a few minutes, you can set up builds, tests,
   and automatic App Store and beta deployments for your project, all running in
   the cloud on every pull request and commit. Try it for free today.
   
   
   LOGIC INTERTWINED WITH VIEWS
   
   “You shouldn’t put business logic within your views”, is a piece of advice
   that’s often mentioned when discussing unit testing within the context of
   UI-based projects, such as iOS and Mac apps. However, in practice, that
   advice can sometimes be tricky to follow, as the most natural or intuitive
   place to put view-related logic is often within the views themselves.
   
   As an example, let’s say that we’re working on an app that contains the
   following SendMessageView. Although the actual message sending logic (and its
   associated networking) has already been abstracted using a MessageSender
   protocol, all of the UI-specific logic related to sending messages is
   currently embedded right within our view:
   
   struct SendMessageView: View {
       var sender: MessageSender
   
       @State private var message = ""
   @State private var isSending = false
   @State private var sendingError: Error?
   
       var body: some View {
           VStack {
               Text("Your message:")
   
               TextEditor(text: $message)
   
               Button(isSending ? "Sending..." : "Send") {
                   isSending = true
                   sendingError = nil
               
                   Task {
                       do {
       try await sender.sendMessage(message)
       message = ""
   } catch {
       sendingError = error
   }
   
                       isSending = false
                   }
               }
               .disabled(isSending || message.isEmpty)
   
               if let error = sendingError {
                   Text(error.localizedDescription)
                       .foregroundColor(.red)
               }
           }
       }
   }
   
   At first glance, the above might not look so bad. Our view isn’t massive by
   any stretch of the imagination, and the code is quite well-organized.
   However, unit testing that view’s logic would currently be incredibly
   difficult — as we’d have to find some way to spin up our view within our
   tests, then find its various UI controls (such as its “Send” button), and
   then figure out a way to trigger and observe those views ourselves.
   
   Because we have to remember that SwiftUI views aren’t actual, concrete
   representations of the UI that we’re drawing on-screen, which can then be
   controlled and inspected as we wish. Instead, they’re ephemeral descriptions
   of what we want our various views to look like, which the system then renders
   and manages on our behalf.
   
   So, although we could most likely find a way to unit test our SwiftUI views
   directly — ideally, we’ll probably want to verify our logic in a much more
   controlled, isolated environment.
   
   One way to create such an isolated environment would be to extract all of the
   logic that we’re looking to test out from our views, and into objects and
   functions that are under our complete control — for example by using a view
   model. Here’s what such a view model could end up looking like if we were to
   move all of our message sending UI logic out from our SendMessageView:
   
   @MainActor class SendMessageViewModel: ObservableObject {
       @Published var message = ""
   @Published private(set) var errorText: String?
   
   var buttonTitle: String { isSending ? "Sending..." : "Send" }
   var isSendingDisabled: Bool { isSending || message.isEmpty }
   
       private let sender: MessageSender
       private var isSending = false
   
       init(sender: MessageSender) {
           self.sender = sender
       }
   
       func send() {
           guard !message.isEmpty else { return }
           guard !isSending else { return }
   
           isSending = true
           errorText = nil
   
           Task {
               do {
                   try await sender.sendMessage(message)
                   message = ""
               } catch {
                   errorText = error.localizedDescription
               }
   
               isSending = false
           }
       }
   }
   
   To learn more about constructing and using observable objects, check out this
   guide to SwiftUI’s state management system.
   
   Our logic remains almost identical, but the above refactor does give us two
   quite significant benefits. First, we’ll now be able to unit test our code
   without having to worry about SwiftUI at all. And second, we’ll even be able
   to improve our SwiftUI view itself, as our view model now contains all of the
   logic that our view needs to decide how it should be rendered — making that
   UI code much simpler in the process:
   
   struct SendMessageView: View {
       @ObservedObject var viewModel: SendMessageViewModel
   
       var body: some View {
           VStack(alignment: .leading) {
               Text("Your message:")
   
               TextEditor(text: $viewModel.message)
   
               Button(viewModel.buttonTitle) {
                   viewModel.send()
               }
               .disabled(viewModel.isSendingDisabled)
   
               if let errorText = viewModel.errorText {
                   Text(errorText).foregroundColor(.red)
               }
           }
       }
   }
   
   Fantastic! To now shift our focus to unit testing our code, we’re going to
   need two pieces of infrastructure before we can actually start writing our
   test cases. While those two pieces are not strictly required, they’re going
   to help us make our testing code so much simpler and easier to read.
   
   
   INVESTING IN UTILITIES
   
   First, let’s create a mocked implementation of our MessageSender protocol,
   which will enable us to gain complete control over how messages are sent, as
   well as how errors are thrown during that process:
   
   class MessageSenderMock: MessageSender {
       @Published private(set) var pendingMessageCount = 0
       private var pendingMessageContinuations = [CheckedContinuation<Void, Error>]()
   
       func sendMessage(_ message: String) async throws {
           return try await withCheckedThrowingContinuation { continuation in
               pendingMessageContinuations.append(continuation)
               pendingMessageCount += 1
           }
       }
   
       func sendPendingMessages() {
           let continuations = pendingMessageContinuations
           pendingMessageContinuations = []
           pendingMessageCount = 0
           continuations.forEach { $0.resume() }
       }
   
       func triggerError(_ error: Error) {
           let continuations = pendingMessageContinuations
           pendingMessageContinuations = []
           pendingMessageCount = 0
           continuations.forEach { $0.resume(throwing: error) }
       }
   }
   
   To learn more about Swift’s continuation system, check out “Connecting
   async/await to other Swift code”.
   
   Next, since the code that we’re looking to verify is asynchronous, we’re
   going to need a way to wait for a given state to be entered before proceeding
   with our verifications. Since we don’t want to put any observation logic
   within our tests themselves, let’s extend XCTestCase with a method that’ll
   let us wait until a given @Published-marked property has been assigned a
   specific value:
   
   extension XCTestCase {
       func waitUntil<T: Equatable>(
           _ propertyPublisher: Published<T>.Publisher,
           equals expectedValue: T,
           timeout: TimeInterval = 10,
           file: StaticString = #file,
           line: UInt = #line
       ) {
           let expectation = expectation(
               description: "Awaiting value \(expectedValue)"
           )
           
           var cancellable: AnyCancellable?
   
           cancellable = propertyPublisher
               .dropFirst()
               .first(where: { $0 == expectedValue })
               .sink { value in
                   XCTAssertEqual(value, expectedValue, file: file, line: line)
                   cancellable?.cancel()
                   expectation.fulfill()
               }
   
           waitForExpectations(timeout: timeout, handler: nil)
       }
   }
   
   Above we’re using Apple’s Combine framework to observe the injected Published
   property’s publisher (wow, that’s quite a tongue twister, isn’t it?). To
   learn more about Combine, and published properties in particular, check out
   this Discover page.
   
   With those two pieces in place, we can now finally start writing the unit
   tests for our UI-related message sending logic! It might, at first, seem
   rather unnecessary to create all of that infrastructure just to be able to
   verify some simple pieces of logic — but the utilities that we’ve now created
   will really make our testing code much easier (and more enjoyable) to write.
   
   
   IT’S TESTING TIME!
   
   Let’s start by verifying that our “Send” button will be correctly enabled and
   disabled based on whether the user has entered a message. To do that, we’ll
   start by setting up an XCTestCase subclass for our tests, and we’ll then be
   able to easily simulate a message being entered simply by assigning a string
   to our view model’s message property:
   
   @MainActor class SendMessageViewModelTests: XCTestCase {
       private var sender: MessageSenderMock!
       private var viewModel: SendMessageViewModel!
   
       @MainActor override func setUp() {
           super.setUp()
           sender = MessageSenderMock()
           viewModel = SendMessageViewModel(sender: sender)
       }
   
       func testSendingDisabledWhileMessageIsEmpty() {
           XCTAssertTrue(viewModel.isSendingDisabled)
           viewModel.message = "Message"
           XCTAssertFalse(viewModel.isSendingDisabled)
           viewModel.message = ""
           XCTAssertTrue(viewModel.isSendingDisabled)
       }
   }
   
   Note that we need to add the MainActor attribute to both our test case
   itself, as well as to the setUp method that we’re overriding from the
   XCTestCase base class. Otherwise we wouldn’t be able to easily interact with
   our view model’s APIs, since those are also bound to the main actor. To learn
   more, check out this article.
   
   Alright, our first test is done, but we’re just getting started. Next, let’s
   verify that the correct states are entered while sending a message — and this
   is where the two utilities that we built earlier (our MessageSenderMock class
   and our waitUntil method) will come very much in handy:
   
   @MainActor class SendMessageViewModelTests: XCTestCase {
       ...
   
       func testSuccessfullySendingMessage() {
           // First, start sending a message, and verify the current state:
           viewModel.message = "Message"
           viewModel.send()
           waitUntil(sender.$pendingMessageCount, equals: 1)
   
           XCTAssertEqual(viewModel.buttonTitle, "Sending...")
           XCTAssertTrue(viewModel.isSendingDisabled)
   
           // Then, finish sending the message, and verify the end state:
           sender.sendPendingMessages()
           waitUntil(viewModel.$message, equals: "")
   
           XCTAssertEqual(viewModel.buttonTitle, "Send")
       }
   }
   
   That’s really the power of investing in testing infrastructure like mocks and
   various utility functions — they let our testing methods remain completely
   linear, and free from cancellables, expectations, and other sources of
   complexity.
   
   Let’s write one more test. This time, we’ll verify that our code behaves
   correctly when an error was encountered:
   
   @MainActor class SendMessageViewModelTests: XCTestCase {
       ...
   
       func testHandlingMessageSendingError() {
           // First, start sending a message:
           viewModel.message = "Message"
           viewModel.send()
           waitUntil(sender.$pendingMessageCount, equals: 1)
   
           // Then, make the sender throw an error and verify it:
           let error = URLError(.badServerResponse)
           sender.triggerError(error)
           waitUntil(viewModel.$errorText, equals: error.localizedDescription)
   
           XCTAssertEqual(viewModel.message, "Message")
           XCTAssertEqual(viewModel.buttonTitle, "Send")
           XCTAssertFalse(viewModel.isSendingDisabled)
       }
   }
   
   Just like that, we’ve now fully covered our UI-related message sending logic
   with unit tests — without having to actually attempt to unit test our SwiftUI
   view itself. As an added bonus, we also made our view code simpler in the
   process, and it should now be much easier to iterate on our view’s logic and
   styling completely separately.
   
   Combine the above approach with a few UI tests, as well as manual testing,
   and we should be able to release new versions of our app with confidence.
   
   
   IS MVVM REQUIRED FOR TESTABILITY?
   
   Now, is the point of the above series of examples that all SwiftUI-based apps
   should completely adopt the MVVM (Model-View-ViewModel) architecture? No,
   absolutely not. Instead, the point is that the easiest way to unit test any
   kind of UI-related code (regardless of what UI framework that the code was
   originally written against) is most often to move that code out from whatever
   view that it’s being consumed in. That way, our logic is no longer tied to
   any specific UI framework, and we’re free to test and manage it however we’d
   like.
   
   To further prove that this article isn’t about advocating for “MVVM all the
   things!”, let’s take a look at another example, in which using a view model
   would probably be quite unnecessary.
   
   Here we’ve written an EventSelectionView, which also has a significant piece
   of logic embedded within it — this time for deciding whether a given Event
   should be auto-selected when the user taps a button:
   
   struct EventSelectionView: View {
       var events: [Event]
       @Binding var selection: Event?
   
       var body: some View {
           List(events) { event in
               ...
           }
           .toolbar {
               Button("Select next available") {
                   selection = events.first(where: { event in
                       guard event.isBookable else {
                           return false
                       }
   
                       guard event.participants.count < event.capacity else {
                           return false
                       }
   
                       return event.startDate > .now
                   })
               }
           }
       }
   }
   
   Just like when we refactored our SendMessageView earlier, one way to make the
   above logic testable would be to create another view model, and move our
   logic there. But, let’s take a different (more lightweight) approach this
   time, and instead move that logic into our Event type itself:
   
   extension Event {
       var isSelectable: Bool {
           guard isBookable else {
               return false
           }
   
           guard participants.count < capacity else {
               return false
           }
   
           return startDate > .now
       }
   }
   
   After all, the above logic isn’t very UI-related at all (it doesn’t mutate
   any form of view state, and it just inspects properties that are owned by
   Event itself), so it doesn’t really warrant the creation of a dedicated view
   model.
   
   And, even without a view model, we can still fully test the above code,
   simply by creating and mutating an Event value:
   
   class EventTests: XCTestCase {
       private var event: Event!
   
       override func setUp() {
           super.setUp()
   
           event = Event(
               id: UUID(),
               capacity: 1,
               isBookable: true,
               startDate: .distantFuture
           )
       }
   
       func testEventIsSelectableByDefault() {
           XCTAssertTrue(event.isSelectable)
       }
   
       func testUnBookableEventIsNotSelectable() {
           event.isBookable = false
           XCTAssertFalse(event.isSelectable)
       }
   
       func testFullyBookedEventIsNotSelectable() {
           event.participants = [.stub()]
           XCTAssertFalse(event.isSelectable)
       }
   
       func testPastEventIsNotSelectable() {
           event.startDate = .distantPast
           XCTAssertFalse(event.isSelectable)
       }
   }
   
   Just like before, a big benefit of performing the above kind of logic
   extraction is that doing so also tends to make our SwiftUI-based code much
   simpler. Thanks to our new Event extension, EventSelectionView can now simply
   use Swift’s key path syntax to pick the first selectable event — like this:
   
   struct EventSelectionView: View {
       var events: [Event]
       @Binding var selection: Event?
   
       var body: some View {
           List(events) { event in
               ...
           }
           .toolbar {
               Button("Select next available") {
                   selection = events.first(where: \.isSelectable)
               }
           }
       }
   }
   
   So, regardless of whether we choose to go for a view model, a simple model
   extension, or another kind of metaphor — if we can move the UI logic that
   we’re looking to test out from our views themselves, then those tests tend to
   be much easier to write and maintain.
   
   Support Swift by Sundell by checking out this sponsor:
   
   Bitrise: Easily set up fast, rock-solid continuous integration for your
   project with Bitrise. In just a few minutes, you can set up builds, tests,
   and automatic App Store and beta deployments for your project, all running in
   the cloud on every pull request and commit. Try it for free today.
   
   
   CONCLUSION
   
   So, how do I unit test my SwiftUI views? The answer is quite simply: I don’t.
   I also almost never test my UIView implementations either. Instead, I focus
   on extracting all of the logic that I wish to test out from my views and into
   objects that are under my complete control. That way, I can spend less time
   fighting with Apple’s UI frameworks in order to make them unit
   testing-friendly, and more time writing solid, reliable tests.
   
   I hope that this article has given you a few ideas on how you could make your
   SwiftUI-based code easier to test as well. If you have any questions,
   comments, or feedback, then feel free to reach out via either Twitter or
   email.
   
   Thanks for reading!


 * * SWIFTUI
     
     Get the most out of Apple’s new UI framework.
   
   
   * UNIT TESTING
     
     Building fast and stable unit testing suites using XCTest.
   
   * Listen to a podcast episode about swiftui
     
     
     98: “AN ENTIRE SPECTRUM OF APPS” WITH SPECIAL GUEST SEAN ALLEN

 * Support Swift by Sundell by checking out this sponsor:
   
   Bitrise: Easily set up fast, rock-solid continuous integration for your
   project with Bitrise. In just a few minutes, you can set up builds, tests,
   and automatic App Store and beta deployments for your project, all running in
   the cloud on every pull request and commit. Try it for free today.


 * COMBINING PROTOCOLS IN SWIFT
   
    * protocols
    * generics
   
   Published on 09 Feb 2022
   Basics article available: Protocols
   
   One of the core strengths of Swift’s protocols is that they enable us to
   define shared interfaces that multiple types can conform to, which in turn
   lets us interact with those types in a very uniform way, without necessarily
   knowing what underlying type that we’re currently dealing with.
   
   For example, to clearly define an API that enables us to persist a given
   instance onto disk, we might choose to use a protocol that looks something
   like this:
   
   protocol DiskWritable {
       func writeToDisk(at url: URL) throws
   }
   
   One advantage of defining commonly used APIs that way is that it helps us
   keep our code consistent, as we can now make any type that should be
   disk-writable conform to the above protocol, which then requires us to
   implement the exact same method for all such types.
   
   Another big advantage of Swift protocols is that they’re extendable, which
   makes it possible for us to define all sorts of convenience APIs for both our
   own protocols, as well as those that are defined externally — for example
   within the standard library, or within any framework that we’ve imported.
   
   When writing those kinds of convenience APIs, we might also want to mix the
   protocol that we’re currently extending with some functionality provided by
   another protocol. For example, let’s say that we wanted to provide a default
   implementation of our DiskWritable protocol’s writeToDisk method for types
   that also conform to the Encodable protocol — since a type that’s encodable
   can be transformed into Data, which we could then automatically write to
   disk.
   
   One way to make that happen would be to make our DiskWritable protocol
   inherit from Encodable, which in turn will require all conforming types to
   implement both of those two protocols’ requirements. We could then simply
   extend DiskWritable in order to add that default implementation of
   writeToDisk that we were looking to provide:
   
   protocol DiskWritable: Encodable {
       func writeToDisk(at url: URL) throws
   }
   
   extension DiskWritable {
       func writeToDisk(at url: URL) throws {
           let encoder = JSONEncoder()
           let data = try encoder.encode(self)
           try data.write(to: url)
       }
   }
   
   While powerful, the above approach does have a quite significant downside, in
   that we’ve now completely coupled our DiskWritable protocol with Encodable —
   meaning that we can no longer use that protocol by itself, without also
   requiring any conforming type to also fully implement Encodable, which might
   become problematic.
   
   Another, much more flexible approach would be to let DiskWritable remain a
   completely stand-alone protocol, and instead write a type-constrained
   extension that only adds our default writeToDisk implementation to types that
   also conform to Encodable separately — like this:
   
   extension DiskWritable where Self: Encodable {
       func writeToDisk(at url: URL) throws {
           let encoder = JSONEncoder()
           let data = try encoder.encode(self)
           try data.write(to: url)
       }
   }
   
   The tradeoff here is that the above approach does require each type that
   wants to leverage our default writeToDisk implementation to explicitly
   conform to both DiskWritable and Encodable, which might not be a big deal,
   but it could make it a bit harder to discover that default implementation —
   since it’s no longer automatically available on all DiskWritable-conforming
   types.
   
   One way to address that discoverability issue, though, could be to create a
   convenience type alias (using Swift’s protocol composition operator, &) that
   gives us an indication that DiskWritable and Encodable can be combined to
   unlock new functionality:
   
   typealias DiskWritableByEncoding = DiskWritable & Encodable
   
   When a type conforms to those two protocols (either using the above type
   alias, or completely separately), it’ll now get access to our default
   writeToDisk implementation (while still having the option to provide its own,
   custom implementation as well):
   
   struct TodoList: DiskWritableByEncoding {
       var name: String
       var items: [Item]
       ...
   }
   
   let list = TodoList(...)
   try list.writeToDisk(at: fileURL)
   
   Combining protocols like that can be a really powerful technique, as we’re
   not just limited to adding default implementations of protocol requirements —
   we can also add brand new APIs to any protocol combination, simply by adding
   new methods or computed properties within one of our extensions.
   
   For example, here we’ve added a second overload of our writeToDisk method,
   which makes it possible to pass a custom JSONEncoder that’ll be used when
   serializing the current instance:
   
   extension DiskWritable where Self: Encodable {
       func writeToDisk(at url: URL, encoder: JSONEncoder) throws {
           let data = try encoder.encode(self)
           try data.write(to: url)
       }
   
       func writeToDisk(at url: URL) throws {
           try writeToDisk(at: url, encoder: JSONEncoder())
       }
   }
   
   We do have to be bit careful not to over-use the above pattern, though, since
   doing so could introduce conflicts if a given type ends up getting access to
   multiple default implementations of the same method.
   
   To illustrate, let’s say that our code base also contains a DataConvertible
   protocol, which we’d like to extend with a similar, default implementation of
   writeToDisk — like this:
   
   protocol DataConvertible {
       func convertToData() throws -> Data
   }
   
   extension DiskWritable where Self: DataConvertible {
       func writeToDisk(at url: URL) throws {
           let data = try convertToData()
           try data.write(to: url)
       }
   }
   
   While both of the two DiskWritable extensions that we’ve now created make
   perfect sense in isolation, we’ll now end up with a conflict if a given
   DiskWritable-conforming type also wants to conform to both Encodable and
   DataConvertible at the same time (which is highly likely, since both of those
   protocols are about transforming an instance into Data).
   
   Since the compiler won’t be able to pick which default implementation to use
   in cases like that, we’d have to manually implement our writeToDisk method
   specifically for each of those conflicting types. Not a big problem, perhaps,
   but it could lead us to a situation where it’s hard to tell which method
   implementation that will be used for which type, which in turn could make our
   code feel quite unpredictable and harder to debug and maintain.
   
   So let’s also explore one final, alternative approach to the above set of
   problems — which would be to implement our disk-writing convenience APIs
   within a dedicated type, rather than using protocol extensions. For example,
   here’s how we could define an EncodingDiskWriter, which only requires the
   types that it’ll be used with to conform to Encodable, since the writer
   itself conforms to DiskWritable:
   
   struct EncodingDiskWriter<Value: Encodable>: DiskWritable {
       var value: Value
       var encoder = JSONEncoder()
   
       func writeToDisk(at url: URL) throws {
           let data = try encoder.encode(value)
           try data.write(to: url)
       }
   }
   
   So even though the following Document type doesn’t conform to DiskWritable,
   we can still easily write its data to disk using our new EncodingDiskWriter:
   
   struct Document: Identifiable, Codable {
       let id: UUID
       var name: String
       ...
   }
   
   class EditorViewController: UIViewController {
       private var document: Document
       private var fileURL: URL
       ...
   
       private func save() throws {
           let writer = EncodingDiskWriter(value: document)
   try writer.writeToDisk(at: fileURL)
       }
   }
   
   So, although protocol extensions provide us with an incredibly powerful set
   of tools, it’s always important to remember that there are other alternatives
   that might be a better fit for what we’re trying to build.
   
   Like with so many things in programming, there are no right or wrong answers
   here, but I hope that this article has shown a few different ways to combine
   the functionality of multiple protocols, and what sort of tradeoffs that each
   approach comes with. If you have any questions, comments, or feedback, then
   feel free to send me an email, or reach out via Twitter.
   
   Thanks for reading!
   
   Support Swift by Sundell by checking out this sponsor:
   
   Bitrise: Easily set up fast, rock-solid continuous integration for your
   project with Bitrise. In just a few minutes, you can set up builds, tests,
   and automatic App Store and beta deployments for your project, all running in
   the cloud on every pull request and commit. Try it for free today.


 * * GENERICS
     
     Learn how to fully utilize Swift’s powerful generics system.
   
   * Read more about protocols
     
     
     ASSIGNING TO SELF IN STRUCT INITIALIZERS
   
   * Another article about protocols
     
     
     IMPLEMENTING THROWING PROTOCOL FUNCTIONS AS NON-THROWING


 * MEMORY MANAGEMENT WHEN USING ASYNC/AWAIT IN SWIFT
   
    * concurrency
    * memory management
   
   Published on 03 Feb 2022
   Discover page available: Concurrency
   
   Managing an app’s memory is something that tends to be especially tricky to
   do within the context of asynchronous code, as various objects and values
   often need to be captured and retained over time in order for our
   asynchronous calls to be performed and handled.
   
   While Swift’s relatively new async/await syntax does make many kinds of
   asynchronous operations easier to write, it still requires us to be quite
   careful when it comes to managing the memory for the various tasks and
   objects that are involved in such asynchronous code.
   
   Bitrise: Easily set up fast, rock-solid continuous integration for your
   project with Bitrise. In just a few minutes, you can set up builds, tests,
   and automatic App Store and beta deployments for your project, all running in
   the cloud on every pull request and commit. Try it for free today.
   
   
   IMPLICIT CAPTURES
   
   One interesting aspect of async/await (and the Task type that we need to use
   to wrap such code when calling it from a synchronous context) is how objects
   and values often end up being implicitly captured while our asynchronous code
   is being executed.
   
   For example, let’s say that we’re working on a DocumentViewController, which
   downloads and displays a Document that was downloaded from a given URL. To
   make our download execute lazily when our view controller is about to be
   displayed to the user, we’re starting that operation within our view
   controller’s viewWillAppear method, and we’re then either rendering the
   downloaded document once available, or showing any error that was encountered
   — like this:
   
   class DocumentViewController: UIViewController {
       private let documentURL: URL
       private let urlSession: URLSession
   
       ...
   
       override func viewWillAppear(_ animated: Bool) {
           super.viewWillAppear(animated)
   
           Task {
               do {
                   let (data, _) = try await urlSession.data(from: documentURL)
                   let decoder = JSONDecoder()
                   let document = try decoder.decode(Document.self, from: data)
                   renderDocument(document)
               } catch {
                   showErrorView(for: error)
               }
           }
       }
   
       private func renderDocument(_ document: Document) {
           ...
       }
   
       private func showErrorView(for error: Error) {
           ...
       }
   }
   
   Now, if we just quickly look at the above code, it might not seem like
   there’s any object capturing going on whatsoever. After all, asynchronous
   capturing has traditionally only happened within escaping closures, which in
   turn require us to always explicitly refer to self whenever we’re accessing a
   local property or method within such a closure (when self refers to a class
   instance, that is).
   
   So we might expect that if we start displaying our DocumentViewController,
   but then navigate away from it before its download has completed, that it’ll
   be successfully deallocated once no external code (such as its parent
   UINavigationController) maintains a strong reference to it. But that’s
   actually not the case.
   
   That’s because of the aforementioned implicit capturing that happens whenever
   we create a Task, or use await to wait for the result of an asynchronous
   call. Any object used within a Task will automatically be retained until that
   task has finished (or failed), including self whenever we’re referencing any
   of its members, like we’re doing above.
   
   In many cases, this behavior might not actually be a problem, and will likely
   not lead to any actual memory leaks, since all captured objects will
   eventually be released once their capturing task has completed. However,
   let’s say that we’re expecting the documents downloaded by our
   DocumentViewController to potentially be quite large, and that we wouldn’t
   want multiple view controllers (and their download operations) to remain in
   memory if the user quickly navigates between different screens.
   
   The classic way to address this sort of problem would be to perform a weak
   self capture, which is often accompanied by a guard let self expression
   within the capturing closure itself — in order to turn that weak reference
   into a strong one that can then be used within the closure’s code:
   
   class DocumentViewController: UIViewController {
       ...
   
       override func viewWillAppear(_ animated: Bool) {
           super.viewWillAppear(animated)
   
           Task { [weak self] in
       guard let self = self else { return }
   
               do {
                   let (data, _) = try await self.urlSession.data(
                       from: self.documentURL
                   )
                   let decoder = JSONDecoder()
                   let document = try decoder.decode(Document.self, from: data)
                   self.renderDocument(document)
               } catch {
                   self.showErrorView(for: error)
               }
           }
       }
       
       ...
   }
   
   Unfortunately, that’s not going to work in this case, as our local self
   reference will still be retained while our asynchronous URLSession call is
   suspended, and until all of our closure’s code has finished running (just
   like how a local variable within a function is retained until that scope has
   been exited).
   
   So if we truly wanted to capture self weakly, then we’d have to consistently
   use that weak self reference throughout our closure. To make it somewhat
   simpler to use our urlSession and documentURL properties, we could capture
   those separately, as doing so won’t prevent our view controller itself from
   being deallocated:
   
   class DocumentViewController: UIViewController {
       ...
   
       override func viewWillAppear(_ animated: Bool) {
           super.viewWillAppear(animated)
   
           Task { [weak self, urlSession, documentURL] in
               do {
                   let (data, _) = try await urlSession.data(from: documentURL)
                   let decoder = JSONDecoder()
                   let document = try decoder.decode(Document.self, from: data)
                   self?.renderDocument(document)
               } catch {
                   self?.showErrorView(for: error)
               }
           }
       }
       
       ...
   }
   
   The good news is that, with the above in place, our view controller will now
   be successfully deallocated if it ends up being dismissed before its download
   has completed.
   
   However, that doesn’t mean that its task will automatically be cancelled.
   That might not be a problem in this particular case, but if our network call
   resulted in some kind of side-effect (like a database update), then that code
   would still run even after our view controller would be deallocated, which
   could result in bugs or unexpected behavior.
   
   
   CANCELLING TASKS
   
   One way to ensure that any ongoing download task will indeed be cancelled
   once our DocumentViewController goes out of memory would be to store a
   reference to that task, and to then call its cancel method when our view
   controller is being deallocated:
   
   class DocumentViewController: UIViewController {
       private let documentURL: URL
       private let urlSession: URLSession
       private var loadingTask: Task<Void, Never>?
       
       ...
   
       deinit {
       loadingTask?.cancel()
   }
   
       override func viewWillAppear(_ animated: Bool) {
           super.viewWillAppear(animated)
   
           loadingTask = Task { [weak self, urlSession, documentURL] in
               ...
           }
       }
       
       ...
   }
   
   Now everything works as expected, and all of our view controller’s memory and
   asynchronous state will automatically be cleaned up once it has been
   dismissed — but our code has also become quite complicated in the process.
   Having to write all of that memory management code for every view controller
   that performs an asynchronous task would be quite tedious, and it could even
   make us question whether async/await actually gives us any real benefits over
   technologies like Combine, delegates, or closures.
   
   Thankfully, there’s another way to implement the above pattern that doesn’t
   involve quite as much code and complexity. Since the convention is for
   long-running async methods to throw an error if they get cancelled (see this
   article about delaying asynchronous tasks for more info), we can simply
   cancel our loadingTask once our view controller is about to be dismissed —
   and that will make our task throw an error, exit, and release all of its
   captured objects (including self). That way, we no longer need to capture
   self weakly, or do any other kind of manual memory management work — giving
   us the following implementation:
   
   class DocumentViewController: UIViewController {
       private let documentURL: URL
       private let urlSession: URLSession
       private var loadingTask: Task<Void, Never>?
       
       ...
   
       override func viewWillAppear(_ animated: Bool) {
           super.viewWillAppear(animated)
   
           loadingTask = Task {
               do {
                   let (data, _) = try await urlSession.data(from: documentURL)
                   let decoder = JSONDecoder()
                   let document = try decoder.decode(Document.self, from: data)
                   renderDocument(document)
               } catch {
                   showErrorView(for: error)
               }
           }
       }
   
       override func viewWillDisappear(_ animated: Bool) {
       super.viewWillDisappear(animated)
       loadingTask?.cancel()
   }
   
       ...
   }
   
   Note that when our task is cancelled, our showErrorView method will now still
   be called (since an error will be thrown, and self remains in memory at that
   point). However, that extra method call should be completely negligible in
   terms of performance.
   
   
   LONG-RUNNING OBSERVATIONS
   
   The above set of memory management techniques should become even more
   important once we start using async/await to set up long-running observations
   of some kind of async sequence or stream. For example, here we’re making a
   UserListViewController observe a UserList class in order to reload its table
   view data once an array of User models was changed:
   
   class UserList: ObservableObject {
       @Published private(set) var users: [User]
       ...
   }
   
   class UserListViewController: UIViewController {
       private let list: UserList
       private lazy var tableView = UITableView()
       
       ...
   
       override func viewWillAppear(_ animated: Bool) {
           super.viewWillAppear(animated)
   
           Task {
               for await users in list.$users.values {
                   updateTableView(withUsers: users)
               }
           }
       }
   
       private func updateTableView(withUsers users: [User]) {
           ...
       }
   }
   
   To learn more about Published properties, check out this article.
   
   Note that the above implementation currently doesn’t include any of the task
   cancellation logic that we previously implemented within our
   DocumentViewController, which in this case will actually lead to a memory
   leak. The reason is that (unlike our previous Document-loading task) our
   UserList observation task will keep running indefinitely, as it’s iterating
   over a Publisher-based async sequence that can’t throw an error, or complete
   in any other way.
   
   The good news is that we can easily fix the above memory leak using the exact
   same technique as we previously used to prevent our DocumentViewController
   from being retained in memory — that is, to cancel our observation task once
   our view controller is about to disappear:
   
   class UserListViewController: UIViewController {
       private let list: UserList
       private lazy var tableView = UITableView()
       private var observationTask: Task<Void, Never>?
   
       ...
   
       override func viewWillAppear(_ animated: Bool) {
           super.viewWillAppear(animated)
   
           observationTask = Task {
               for await users in list.$users.values {
                   updateTableView(withUsers: users)
               }
           }
       }
   
       override func viewWillDisappear(_ animated: Bool) {
           super.viewWillDisappear(animated)
           observationTask?.cancel()
       }
   
       ...
   }
   
   Note that performing the above cancellation within deinit wouldn’t work in
   this case, since we’re dealing with an actual memory leak — meaning that
   deinit will never be called unless we break our observation task’s endless
   loop.
   
   Support Swift by Sundell by checking out this sponsor:
   
   Bitrise: Easily set up fast, rock-solid continuous integration for your
   project with Bitrise. In just a few minutes, you can set up builds, tests,
   and automatic App Store and beta deployments for your project, all running in
   the cloud on every pull request and commit. Try it for free today.
   
   
   CONCLUSION
   
   At first, it might seem like technologies like Task and async/await make
   asynchronous, memory-related issues a thing of the past, but unfortunately we
   still have to be careful around how objects are captured and retained when
   performing various kinds of async-marked calls. While actual memory leaks and
   retain cycles are perhaps not as easily encountered as when using things like
   Combine or closures, we still have to ensure that our objects and tasks are
   managed in a way that makes our code robust and easy to maintain.
   
   I hope that you found this article useful. If you did, please share it! If
   you have any questions, comments, or feedback, then feel free to reach out
   via either Twitter or email.
   
   Thanks for reading!

 * * Watch a short video clip about concurrency
     
     
     SWIFT CLIP: DISPATCH QUEUES
     
     Writing asynchronous code using dispatch queues and work items.
   
   * Read more about memory management
     
     
     MEMORY MANAGEMENT
   
   * Another article about concurrency
     
     
     USING THE MAINACTOR ATTRIBUTE TO AUTOMATICALLY DISPATCH UI UPDATES ON THE
     MAIN QUEUE

 * Support Swift by Sundell by checking out this sponsor:
   
   Bitrise: Easily set up fast, rock-solid continuous integration for your
   project with Bitrise. In just a few minutes, you can set up builds, tests,
   and automatic App Store and beta deployments for your project, all running in
   the cloud on every pull request and commit. Try it for free today.


 * AUTOMATICALLY RETRYING AN ASYNCHRONOUS SWIFT TASK
   
    * concurrency
   
   Published on 25 Jan 2022
   Discover page available: Concurrency
   
   Sometimes, we might want to automatically retry an asynchronous operation
   that failed, for example in order to work around temporary network problems,
   or to re-establish some form of connection.
   
   Here we’re doing just that when using Apple’s Combine framework to implement
   a network call, which we’ll retry up to 3 times before handling any error
   that was encountered:
   
   struct SettingsLoader {
       var url: URL
       var urlSession = URLSession.shared
       var decoder = JSONDecoder()
   
       func load() -> AnyPublisher<Settings, Error> {
           urlSession
               .dataTaskPublisher(for: url)
               .map(\.data)
               .decode(type: Settings.self, decoder: decoder)
               .retry(3)
               .eraseToAnyPublisher()
       }
   }
   
   Note that the above example will unconditionally retry our loading operation
   (up to 3 times) regardless of what kind of error that was thrown.
   
   But what if we wanted to implement something similar, but using Swift
   Concurrency instead? While Combine’s Publisher protocol includes the above
   retry operator as a built-in API, neither of Swift’s new concurrency APIs
   offer something similar (at least not at the time of writing), so we’ll have
   to get creative!
   
   One really neat aspect of Swift’s new concurrency system, and async/await in
   particular, is that it enables us to mix various asynchronous calls with
   standard control flow constructs, such as if statements and for loops. So,
   one way to implement automatic retries for await-marked calls would be to
   place the asynchronous code that we want to run within a loop that iterates
   over a range, which in turn describes how many retries that we wish to
   perform — like this:
   
   struct SettingsLoader {
       var url: URL
       var urlSession = URLSession.shared
       var decoder = JSONDecoder()
   
       func load() async throws -> Settings {
           // Perform 3 attempts, and retry on any failure:
           for _ in 0..<3 {
               do {
                   return try await performLoading()
               } catch {
                   // This 'continue' statement isn't technically
                   // required, but makes our intent more clear:
                   continue
               }
           }
   
           // The final attempt (which throws its error if it fails):
           return try await performLoading()
       }
   
       private func performLoading() async throws -> Settings {
           let (data, _) = try await urlSession.data(from: url)
           return try decoder.decode(Settings.self, from: data)
       }
   }
   
   The above implementation works perfectly fine, but if we’re looking to add
   the same kind of retrying logic in multiple places throughout a project, then
   it might be worth moving that code into some form of utility that could be
   easily reused.
   
   One way to do just that would be to extend Swift’s Task type with a
   convenience API that lets us quickly create such auto-retrying tasks. Our
   actual logic can remain almost identical to what it was before, but we’ll
   parameterize the maximum number of retries, and we’ll also add support for
   cancellation as well:
   
   extension Task where Failure == Error {
       @discardableResult
       static func retrying(
           priority: TaskPriority? = nil,
           maxRetryCount: Int = 3,
           operation: @Sendable @escaping () async throws -> Success
       ) -> Task {
           Task(priority: priority) {
               for _ in 0..<maxRetryCount {
                   try Task<Never, Never>.checkCancellation()
   
                   do {
                       return try await operation()
                   } catch {
                       continue
                   }
               }
   
               try Task<Never, Never>.checkCancellation()
               return try await operation()
           }
       }
   }
   
   That’s already a really useful, and completely reusable implementation, but
   let’s take things one step further, shall we?
   
   When retrying asynchronous operations, it’s very common to want to add a bit
   of delay between each retry — perhaps in order to give an external system
   (such as a server) a chance to recover from some kind of error before we make
   another attempt at calling it. So let’s also add support for such delays,
   which can easily be done using the built-in Task.sleep API:
   
   extension Task where Failure == Error {
       @discardableResult
       static func retrying(
           priority: TaskPriority? = nil,
           maxRetryCount: Int = 3,
           retryDelay: TimeInterval = 1,
           operation: @Sendable @escaping () async throws -> Success
       ) -> Task {
           Task(priority: priority) {
               for _ in 0..<maxRetryCount {
                   do {
                       return try await operation()
                   } catch {
                       let oneSecond = TimeInterval(1_000_000_000)
   let delay = UInt64(oneSecond * retryDelay)
   try await Task<Never, Never>.sleep(nanoseconds: delay)
   
                       continue
                   }
               }
   
               try Task<Never, Never>.checkCancellation()
               return try await operation()
           }
       }
   }
   
   Note how we can now remove the checkCancellation call at the start of our for
   loop, since our Task.sleep call will automatically throw an error if the task
   was cancelled. To learn more about delaying Task instances, check out
   “Delaying an asynchronous Swift Task”.
   
   If we wanted to, we could’ve also added the “semi-public”
   @_implicitSelfCapture attribute to our operation closure, which would give it
   the same implicit-self-capturing behavior as when passing a closure directly
   to the Task type itself.
   
   However, that’s not really something that I recommend doing (given that
   underscored attributes can change at any point), so let’s instead wrap things
   up by refactoring the SettingsLoader example from before to instead use our
   new Task extension to perform its retries:
   
   struct SettingsLoader {
       var url: URL
       var urlSession = URLSession.shared
       var decoder = JSONDecoder()
   
       func load() async throws -> Settings {
           try await Task.retrying {
               let (data, _) = try await urlSession.data(from: url)
               return try decoder.decode(Settings.self, from: data)
           }
           .value
       }
   }
   
   Very nice! Note how we can use a given task’s value property to observe its
   returned value (or re-throw any error that was thrown within the task
   itself).
   
   Bitrise: Easily set up fast, rock-solid continuous integration for your
   project with Bitrise. In just a few minutes, you can set up builds, tests,
   and automatic App Store and beta deployments for your project, all running in
   the cloud on every pull request and commit. Try it for free today.
   
   
   CONCLUSION
   
   There are of course lots of ways that we could take this article’s Task
   extension further — for example by making it possible to only retry on
   certain errors (perhaps by enabling us to pass something like an
   retryPredicate closure when creating our task?) — but I hope that this
   article has given you a few ideas on how you could implement auto-retrying
   tasks within your projects.
   
   If you have any questions, comments, or feedback, then feel free to reach out
   via either Twitter or email.
   
   Thanks for reading!


 * * CONCURRENCY
     
     Explore Swift’s built-in concurrency system.
   
   * Listen to a podcast episode about concurrency
     
     
     108: “CONCURRENCY AND SWIFT-DOCC” WITH SPECIAL GUEST MARIN TODOROV
   
   * Read more about concurrency
     
     
     BUILDING AN ASYNCHRONOUS SWIFTUI BUTTON


 * BACKGROUNDS AND OVERLAYS IN SWIFTUI
   
    * swiftui
   
   Published on 20 Jan 2022
   Discover page available: SwiftUI
   
   SwiftUI offers several different ways for us to create stacks of overlapping
   views that can be arranged along the Z axis, which in turn enables us to
   define various kinds of overlays and backgrounds for the views that we build.
   Let’s explore some of those built-in stacking methods and what sort of UIs
   that they enable us to create.
   
   Bitrise: Easily set up fast, rock-solid continuous integration for your
   project with Bitrise. In just a few minutes, you can set up builds, tests,
   and automatic App Store and beta deployments for your project, all running in
   the cloud on every pull request and commit. Try it for free today.
   
   
   ZSTACKS
   
   Like its name implies, SwiftUI’s ZStack type is the Z-axis equivalent of the
   horizontally-oriented HStack and the vertical VStack. When placing multiple
   views within a ZStack, they’re (by default) rendered back-to-front, with the
   first view being placed at the back. For example, here we’re creating a
   full-screen ContentView, which renders a gradient with a text stacked on top:
   
   Preview
   
   struct ContentView: View {
       var body: some View {
           ZStack {
               LinearGradient(
                   colors: [.orange, .red],
                   startPoint: .topLeading,
                   endPoint: .bottomTrailing
               )
               .ignoresSafeArea()
   
               Text("Swift by Sundell")
                   .foregroundColor(.white)
                   .font(.title)
           }
       }
   }
   
   Tip: You can use the above code sample’s PREVIEW button to see what it’ll
   look like when rendered.
   
   The reason that the above ContentView is rendered across all of the available
   screen space is because a LinearGradient will always occupy as much space as
   possible by default, and since a any stack’s size defaults to the total size
   of its children, that leads to our ZStack being resized to occupy that same
   full-screen space.
   
   
   THE BACKGROUND MODIFIER
   
   However, sometimes we might not want a given background to stretch out to
   fill all available space, and while we could address that by applying various
   sizing modifiers to our background view, SwiftUI ships with a built-in tool
   that automatically resizes a given view’s background to perfectly fit its
   parent — the background modifier.
   
   Here’s how we could use that modifier to instead apply our LinearGradient
   background directly to our Text-based view, which makes that background take
   on the exact same size as our text itself (including its padding):
   
   Preview
   
   struct ContentView: View {
       var body: some View {
           Text("Swift by Sundell")
               .foregroundColor(.white)
               .font(.title)
               .padding(35)
               .background(
       LinearGradient(
           colors: [.orange, .red],
           startPoint: .topLeading,
           endPoint: .bottomTrailing
       )
   )
       }
   }
   
   The reason that the padding is included when calculating our background’s
   size in the above example is because we’re applying the padding modifier
   before adding our background. To learn more about that, check out “When does
   the order of SwiftUI modifiers matter, and why?”.
   
   One thing that’s important to point out, though, is that even though a view’s
   background does indeed get resized according to the parent view itself,
   there’s no form of clipping applied by default. So if we were to give our
   LinearGradient an explicit size that’s larger than its parent, then it’ll
   actually be rendered out of bounds (which we can clearly demonstrate by
   adding a border to our main Text-based view):
   
   Preview
   
   struct ContentView: View {
       var body: some View {
           Text("Swift by Sundell")
               .foregroundColor(.white)
               .font(.title)
               .padding(35)
               .background(
                   LinearGradient(
                       colors: [.orange, .red],
                       startPoint: .topLeading,
                       endPoint: .bottomTrailing
                   )
                   .frame(width: 300, height: 300)
               )
               .border(Color.blue)
       }
   }
   
   There are multiple ways to apply clipping to a view, though, which would
   remove the above sort of out-of-bounds rendering. For example, we could use
   either the clipped or clipShape modifier to tell the view to apply a clipping
   mask to its bounds, or we could give our view rounded corners (which also
   introduces clipping) — like this:
   
   Preview
   
   struct ContentView: View {
       var body: some View {
           Text("Swift by Sundell")
               .foregroundColor(.white)
               .font(.title)
               .padding(35)
               .background(
                   LinearGradient(
                       colors: [.orange, .red],
                       startPoint: .topLeading,
                       endPoint: .bottomTrailing
                   )
                   .frame(width: 300, height: 300)
               )
               .cornerRadius(20)
       }
   }
   
   Of course, the simplest way to avoid drawing a background outside of the
   bounds of its parent view is to simply let the SwiftUI layout system
   automatically determine the size of each background. That way, the size of a
   given background will always perfectly match the size of its parent view.
   
   
   ASSIGNING OVERLAYS
   
   SwiftUI also supports adding overlays to views as well, which essentially act
   as the inverse of backgrounds — in that they’re rendered on top of their
   parent views (with the same sizing behaviors as we explored above).
   
   Both overlays and backgrounds also support alignment customization, which
   lets us decide how such a view should be placed within its parent’s
   coordinate system. For views that are fully resizable (like our above
   LinearGradient), the alignment doesn’t matter (since those views will be
   resized to fit their parent view anyway), but for smaller views, specifying
   an alignment lets us move a view to any of its parent’s corners.
   
   For example, here’s how we could add a star image overlay to the top-trailing
   corner of our ContentView:
   
   Preview
   
   struct ContentView: View {
       var body: some View {
           Text("Swift by Sundell")
               .foregroundColor(.white)
               .font(.title)
               .padding(35)
               .background(
                   LinearGradient(
                       colors: [.orange, .red],
                       startPoint: .topLeading,
                       endPoint: .bottomTrailing
                   )
               )
               .overlay(starOverlay, alignment: .topTrailing)
               .cornerRadius(20)
       }
   
       private var starOverlay: some View {
           Image(systemName: "star")
       .foregroundColor(.white)
       .padding([.top, .trailing], 5)
       }
   }
   
   Specifying an alignment for a background is done the exact same way, by
   passing an alignment argument when using the background modifier.
   
   An overlay or background also inherits all of its parent’s environment
   values. In the case of our ContentView example, that means that we don’t
   actually have to apply the same foregroundColor modifier twice, like we’re
   doing above (since foreground colors automatically become part of the SwiftUI
   environment). So if we instead apply that modifier after we’ve added our
   overlay, then that same color will be applied to both our text and our star
   icon:
   
   struct ContentView: View {
       var body: some View {
           Text("Swift by Sundell")
               .font(.title)
               .padding(35)
               .background(
                   LinearGradient(
                       colors: [.orange, .red],
                       startPoint: .topLeading,
                       endPoint: .bottomTrailing
                   )
               )
               .overlay(starOverlay, alignment: .topTrailing)
               .foregroundColor(.white)
               .cornerRadius(20)
       }
   
       private var starOverlay: some View {
           Image(systemName: "star")
               .padding([.top, .trailing], 5)
       }
   }
   
   
   CONDITIONAL OVERLAYS AND BACKGROUNDS
   
   Sometimes, though, we might only want to apply a given overlay (or
   background) under certain conditions. For example, let’s say that we wanted
   to add a second overlay that displays a progress view while our ContentView
   is in some form of loading state.
   
   Since we don’t want to introduce any if/else control flow to our ContentView
   itself (since that’ll essentially make SwiftUI treat those two code paths as
   two separate views), we could create such a conditional overlay by defining a
   new @ViewBuilder-marked computed property — like this:
   
   Preview
   
   struct ContentView: View {
       @State private var isLoading = true
   
       var body: some View {
           Text("Swift by Sundell")
               .font(.title)
               .padding(35)
               .background(
                   LinearGradient(
                       colors: [.orange, .red],
                       startPoint: .topLeading,
                       endPoint: .bottomTrailing
                   )
               )
               .overlay(starOverlay, alignment: .topTrailing)
               .overlay(loadingOverlay)
               .foregroundColor(.white)
               .cornerRadius(20)
       }
       
       ...
   
       @ViewBuilder private var loadingOverlay: some View {
           if isLoading {
       ProgressView()
   }
       }
   }
   
   Note that it’s perfectly fine to apply multiple overlays or backgrounds to a
   single view. They’ll simply be stacked on top of each other, just like when
   using a ZStack.
   
   However, our ProgressView isn’t currently very easy to see, and could
   definitely use a background of its own. In this case, we do actually want
   that background to occupy the same space as our ContentView itself, which can
   be done using the ZStack-based technique that we initially explored in this
   article:
   
   Preview
   
   struct ContentView: View {
       ...
   
       @ViewBuilder private var loadingOverlay: some View {
           if isLoading {
               ZStack {
       Color(white: 0, opacity: 0.75)
       ProgressView().tint(.white)
   }
           }
       }
   }
   
   Note that if our app supported iOS 14 or earlier, then we’d have to apply
   CircularProgressViewStyle(tint: .white) to our progress view (using the
   progressViewStyle modifier), rather than using tint, since that modifier was
   introduced in iOS 15.
   
   iOS 15 also introduced new APIs for defining backgrounds and overlays using
   @ViewBuilder-marked closures. The benefit of those new APIs is that they let
   us use control flow (like if statements) inline within those modifier calls,
   which in our case would enable us to easily define both of our two overlays
   right within our view’s body:
   
   struct ContentView: View {
       @State private var isLoading = true
   
       var body: some View {
           Text("Swift by Sundell")
               .font(.title)
               .padding(35)
               .background(
                   LinearGradient(
                       colors: [.orange, .red],
                       startPoint: .topLeading,
                       endPoint: .bottomTrailing
                   )
               )
               .overlay(alignment: .topTrailing) {
       Image(systemName: "star")
           .padding([.top, .trailing], 5)
   }
   .overlay {
       if isLoading {
           ZStack {
               Color(white: 0, opacity: 0.75)
               ProgressView().tint(.white)
           }
       }
   }
               .foregroundColor(.white)
               .cornerRadius(20)
       }
   }
   
   That’s not to say that delegating certain accessory view definitions to
   separate properties isn’t a good idea — in fact, that’s an excellent pattern
   that can help us break certain massive body properties up into more
   manageable pieces (without having to define a ton of new view types). But
   sometimes, defining everything inline might be the way to go, especially for
   simpler overlays, and the new closure-based background and overlay modifiers
   certainly make doing so much easier.
   
   
   CLOSURE-BASED BACKWARD COMPATIBILITY
   
   It is a bit of a shame that those new closure-based APIs are iOS 15-only,
   though, so let’s wrap up this article by fixing that. It’s important to
   remember just how composable SwiftUI was designed to be, and that most of the
   convenience APIs that have been introduced recently are merely composing some
   of SwiftUI’s older building blocks — which is something that we can do
   ourselves as well.
   
   So here’s how we could use the same technique as we previously used to make
   certain async/await-based system APIs backward compatible — that is, by
   defining an extension that overrides the system-provided APIs with our own,
   iOS 13-compatible versions:
   
   @available(iOS, deprecated: 15.0, message: "Use the built-in APIs instead")
   extension View {
       func background<T: View>(
           alignment: Alignment = .center,
           @ViewBuilder content: () -> T
       ) -> some View {
           background(Group(content: content), alignment: alignment)
       }
   
       func overlay<T: View>(
           alignment: Alignment = .center,
           @ViewBuilder content: () -> T
       ) -> some View {
           overlay(Group(content: content), alignment: alignment)
       }
   }
   
   With that simple extension in place, we can now use the closure-based
   variants of both background and overlay even within projects that need to
   support earlier operating system versions.
   
   Support Swift by Sundell by checking out this sponsor:
   
   Bitrise: Easily set up fast, rock-solid continuous integration for your
   project with Bitrise. In just a few minutes, you can set up builds, tests,
   and automatic App Store and beta deployments for your project, all running in
   the cloud on every pull request and commit. Try it for free today.
   
   
   CONCLUSION
   
   Backgrounds and overlays are two incredibly useful layout tools when working
   with SwiftUI, and along with ZStack, make it possible to define all sorts of
   depth-stacked view hierarchies. To learn more about SwiftUI’s layout system,
   make sure to check out my three-part guide right here, and head over to the
   SwiftUI Discover page if you’d like to continue exploring many other aspects
   of the framework.
   
   Of course, you’re always welcome to contact me via either Twitter or email if
   you have any questions, comments, or feedback.
   
   Thanks for reading!


 * * SWIFTUI
     
     Get the most out of Apple’s new UI framework.
   
   * Listen to a podcast episode about swiftui
     
     
     57: “AUDIO AND SWIFT” WITH SPECIAL GUEST ADAM BELL
     
     From 80s-style synths to SwiftUI.
   
   * Read more about swiftui
     
     
     ADDING SWIFTUI’S VIEWBUILDER ATTRIBUTE TO FUNCTIONS
     
     Really useful for utility methods.

 * Support Swift by Sundell by checking out this sponsor:
   
   Bitrise: Easily set up fast, rock-solid continuous integration for your
   project with Bitrise. In just a few minutes, you can set up builds, tests,
   and automatic App Store and beta deployments for your project, all running in
   the cloud on every pull request and commit. Try it for free today.


 * BASICS: LOOPS
   
    * Basics
    * collections
    * language features
   
   Published on 13 Jan 2022
   
   Swift offers many different built-in ways to iterate over collections (such
   as arrays, sets, and dictionaries) — the most basic of which being for loops,
   which let us run a piece of code for each element that was found within a
   given collection. For example, here we’re looping through an array of names,
   and we’re then outputting each name by printing it into the console:
   
   let names = ["John", "Emma", "Robert", "Julia"]
   
   for name in names {
       print(name)
   }
   
   An alternative way of accomplishing the same thing would be to instead call
   the forEach method on our array of names, which lets us pass a closure
   that’ll be run for each element:
   
   names.forEach { name in
       print(name)
   }
   
   One key difference between a for loop and forEach, though, is that the latter
   doesn’t enable us to break the iteration in order to stop it once a given
   condition has been met. For example, when going back to using a for loop
   again, we could decide to stop the iteration once the name Robert was
   encountered:
   
   let names = ["John", "Emma", "Robert", "Julia"]
   
   for name in names {
       if name == "Robert" {
       break
   }
   
       print(name) // Will only print "John" and "Emma"
   }
   
   There are also many other ways to use for loops in Swift. For example, if
   we’d like to gain access to what index that we’re currently handling as part
   of our iteration, then we could instead choose to base our loop on a range
   that goes from zero to the number of elements within our collection. We could
   then use the Array type’s subscripting feature to retrieve the current
   element for that index — like this:
   
   for index in 0..<names.count {
       print(index, names[index])
   }
   
   Another way to write the exact same loop would be to instead iterate over our
   array’s indicies, rather than constructing a range manually:
   
   for index in names.indices {
       print(index, names[index])
   }
   
   Yet another approach would be to use the enumerated method to convert our
   array into a sequence containing tuples that pair each index with its
   associated element:
   
   for (index, name) in names.enumerated() {
       print(index, name)
   }
   
   Note that the enumerated method always uses Int-based offsets, which in the
   case of Array is a perfect match, since that collection also uses Int values
   as its indices.
   
   Next, let’s take a look at while loops, which offer a way for us to
   repeatedly run a block of code as long as a given boolean condition remains
   true. For example, here’s how we could use a while loop to keep appending
   each name within our names array to a string, as long as that string contains
   less than 8 characters:
   
   let names = ["John", "Emma", "Robert", "Julia"]
   var index = 0
   var string = ""
   
   while string.count < 8 {
       string.append(names[index])
       index += 1
   }
   
   print(string) // "JohnEmma"
   
   Another way to construct a while loop (which perhaps isn’t as commonly used
   in Swift as in other languages) is by using a separate repeat block, which
   will also get repeatedly run as long as our while condition evaluates to
   true:
   
   let names = ["John", "Emma", "Robert", "Julia"]
   var index = 0
   var string = ""
   
   repeat {
       string.append(names[index])
       index += 1
   } while string.count < 8
   
   print(string) // "JohnEmma"
   
   The key difference between repeat and a stand-alone while loop is that a
   repeat block will always be run at least once, even if the attached while
   condition initially evaluates to false.
   
   One important thing to keep in mind when using while loops, though, is that
   it’s up to us to make sure that each loop is ended at an appropriate time —
   either by manually using break (like we did earlier when using a for loop),
   or by ensuring that our loop’s boolean condition is met once the iteration
   should be terminated.
   
   For example, when constructing our name-based string value, we probably want
   to make sure that the current index won’t go out of the bounds of our names
   array — since otherwise our app would crash when subscripting into that
   array. One way to do that would be to attach a second boolean condition to
   our while statement — like this:
   
   while string.count < 8, index < names.count {
       string.append(names[index])
       index += 1
   }
   
   Another approach would be to instead perform the above index-check inline
   within the loop itself, for example by using a guard statement that’ll break
   our loop within its else clause:
   
   while string.count < 8 {
       guard index < names.count else {
       break
   }
   
       string.append(names[index])
       index += 1
   }
   
   When working with loops, there’s often many different ways to model the same
   logic, and it can usually be quite useful to prototype a few different
   approaches in order to figure out which one that’ll work best within each
   situation. As an example, we could actually have chosen to implement the
   above iteration using a for loop instead — since we’d be able to attach our
   string.count-based condition to such a loop by using the where keyword:
   
   let names = ["John", "Emma", "Robert", "Julia"]
   var string = ""
   
   for name in names where string.count < 8 {
       string.append(name)
   }
   
   print(string) // "JohnEmma"
   
   That doesn’t mean that the above for-based version is objectively better than
   the while-based one. Picking what type of loop to use is often a matter of
   taste and code structure, although I’d personally argue that whenever a loop
   is based on an actual collection of elements, using a for loop is most often
   the simplest way to go.
   
   Finally, let’s turn our attention to dictionaries, which can also be iterated
   over using the exact same tools that we’ve been using to loop through arrays
   and ranges. When iterating over a dictionary, though, we don’t just get
   access to single elements, but rather (key, value) tuple pairs. For example,
   here’s how we could iterate through a dictionary that contains a
   category-based version of our names dataset:
   
   let namesByCategory = [
       "friends": ["John", "Emma"],
       "family": ["Robert", "Julia"]
   ]
   
   for (category, names) in namesByCategory {
       print(category, names)
   }
   
   Sometimes, though, we might not need access to both the keys and values that
   a given dictionary contains, so it’s also possible to use the _ symbol to
   ignore a given tuple member within our iteration. Here’s how we could do just
   that to ignore our dictionary’s values, and only handle its keys (or
   categories) within our loop:
   
   for (category, _) in namesByCategory {
       print(category)
   }
   
   However, while the above is perfectly valid Swift code, there are actually
   two purpose-built APIs that enable us to perform either a key-only or
   value-only dictionary iteration simply by accessing either the keys or values
   property on the dictionary that we’d like to iterate over:
   
   for category in namesByCategory.keys {
       print(category)
   }
   
   for names in namesByCategory.values {
       print(names)
   }
   
   When working with dictionaries, sets, or other collections that don’t offer a
   guaranteed element order, it’s important to remember that our loops also
   won’t be performed in a predictable order. So, for example, if we’d like to
   ensure that the above category iteration always happens in the same order,
   then we could make that happen by first sorting our dictionary’s keys into an
   array — like this:
   
   for category in namesByCategory.keys.sorted() {
       print(category)
   }
   
   Our categories will now always be iterated over in alphabetical order. Of
   course, performing the above kind of sorting operation is only required if
   the order of elements matters, which will likely only be true for certain
   iterations.
   
   I hope that you found this Basics article useful, and that you learned at
   least one new way of constructing a loop in Swift. For more Basics articles,
   check out this page, and if you have any questions, comments, or feedback
   (even if it’s positive!), then feel free to reach out via either Twitter or
   email.
   
   Thanks for reading!
   
   Support Swift by Sundell by checking out this sponsor:
   
   Bitrise: Easily set up fast, rock-solid continuous integration for your
   project with Bitrise. In just a few minutes, you can set up builds, tests,
   and automatic App Store and beta deployments for your project, all running in
   the cloud on every pull request and commit. Try it for free today.

 * * Read more about collections
     
     
     BINDABLE SWIFTUI LIST ELEMENTS
   
   * Another article about Swift’s language features
     
     
     CALLING INITIALIZERS WITH DOT SYNTAX AND PASSING THEM AS CLOSURES
   
   * Continue exploring Swift’s language features
     
     
     TYPE INFERENCE-POWERED SERIALIZATION IN SWIFT


 * CREATING COMBINE-COMPATIBLE VERSIONS OF ASYNC/AWAIT-BASED APIS
   
    * combine
    * concurrency
   
   Published on 05 Jan 2022
   Discover page available: Combine
   
   A challenge that many developers face as they maintain various code bases
   over time is how to neatly connect different frameworks and APIs in a way
   that properly adheres to the conventions of each technology involved.
   
   For example, as teams around the world are starting to adopt Swift 5.5’s
   async/await-powered concurrency system, we’ll likely find ourselves in
   situations where we need to create versions of our async-marked APIs that are
   compatible with other asynchronous programming techniques — such as Combine.
   
   While we’ve already taken a look at how Combine relates to concurrency APIs
   like async sequences and streams, and how we can make it possible to call
   async-marked functions within a Combine pipeline — in this article, let’s
   explore how we could make it easy to create Combine-based variants of any
   async API, regardless of whether it was defined by us, by Apple, or as part
   of a third-party dependency.
   
   Bitrise: Easily set up fast, rock-solid continuous integration for your
   project with Bitrise. In just a few minutes, you can set up builds, tests,
   and automatic App Store and beta deployments for your project, all running in
   the cloud on every pull request and commit. Try it for free today.
   
   
   ASYNC FUTURES
   
   Let’s say that an app that we’re working on contains the following
   ModelLoader, which can be used to load any Decodable model over the network.
   It performs its work through an async function that looks like this:
   
   class ModelLoader<Model: Decodable> {
       ...
   
       func loadModel(from url: URL) async throws -> Model {
           ...
       }
   }
   
   Now let’s say that we’d also like to create a Combine-based version of the
   above loadModel API, for example in order to be able to call it within
   specific parts of our code base that might’ve been written in a more reactive
   style using the Combine framework.
   
   We could of course choose to write that sort of compatibility code
   specifically for our ModelLoader type, but since this is a general problem
   that we’re likely to encounter multiple times when working with Combine-based
   code, let’s instead create a more generic solution that we’ll be able to
   easily reuse across our code base.
   
   Since we’re dealing with async functions that either return a single value,
   or throw an error, let’s use Combine’s Future publisher to wrap those calls.
   That publisher type was specifically built for these kinds of use cases,
   since it gives us a closure that can be used to report a single Result back
   to the framework.
   
   So let’s go ahead and extend the Future type with a convenience initializer
   that makes it possible to initialize an instance with an async closure:
   
   extension Future where Failure == Error {
       convenience init(operation: @escaping () async throws -> Output) {
           self.init { promise in
               Task {
                   do {
                       let output = try await operation()
                       promise(.success(output))
                   } catch {
                       promise(.failure(error))
                   }
               }
           }
       }
   }
   
   For more information on how Combine’s Future type works, check out “Using
   Combine’s futures and subjects”.
   
   The power of creating an abstraction like that, which isn’t tied to any
   specific use case, is that we’ll now be able to apply it to any async API
   that we want to make Combine-compatible. All it takes is a few lines of code
   that calls the API that we’re looking to bridge within a closure that’s
   passed to our new Future initializer — like this:
   
   extension ModelLoader {
       func modelPublisher(for url: URL) -> Future<Model, Error> {
           Future {
               try await self.loadModel(from: url)
           }
       }
   }
   
   Neat! Note how we could’ve chosen to give that Combine-based version the same
   loadModel name that our async-powered one has (since Swift supports method
   overloading). However, in this case, it might be a good idea to clearly
   separate the two, which is why the above new API has a name that explicitly
   includes the word “Publisher”.
   
   
   REACTIVE ASYNC SEQUENCES
   
   Async sequences and streams are perhaps the closest that the Swift standard
   library has ever come to adopting reactive programming, which in turn makes
   those APIs behave very similarly to Combine — in that they enable us to emit
   values over time.
   
   In fact, in the article “Async sequences, streams, and Combine”, we took a
   look at how Combine publishers can even be directly converted into async
   sequences using their values property — but what if we wanted to go the other
   way, and convert an async sequence (or stream) into a publisher?
   
   Continuing with the ModelLoader example from before, let’s say that our
   loader class also offers the following API, which lets us create an
   AsyncThrowingStream that emits a series of models loaded from an array of
   URLs:
   
   class ModelLoader<Model: Decodable> {
       ...
   
       func loadModels(from urls: [URL]) -> AsyncThrowingStream<Model, Error> {
           ...
       }
   }
   
   For an example of a concrete implementation of an API just like the one
   above, check out the aforementioned article “Async sequences, streams, and
   Combine”.
   
   Just like before, rather than rushing into writing code that specifically
   converts the above loadModels API into a Combine publisher, let’s instead try
   to come up with a generic abstraction that we’ll be able to reuse whenever we
   want to write similar bridging code elsewhere within our project.
   
   This time, we’ll extend Combine’s PassthroughSubject type, which gives us
   complete control over when its values are emitted, as well as when and how it
   should terminate. However, we’re not going to model this API as a convenience
   initializer, since we want to make it clear that calling this API will, in
   fact, make the created subject start emitting values right away. So let’s
   make it a static factory method instead — like this:
   
   extension PassthroughSubject where Failure == Error {
       static func emittingValues<T: AsyncSequence>(
           from sequence: T
       ) -> Self where T.Element == Output {
           let subject = Self()
   
           Task {
               do {
                   for try await value in sequence {
                       subject.send(value)
                   }
   
                   subject.send(completion: .finished)
               } catch {
                   subject.send(completion: .failure(error))
               }
           }
   
           return subject
       }
   }
   
   For more on how static factory methods might differ from initializers in
   terms of API design, check out “Initializers in Swift”
   
   With the above in place, we can now wrap our async stream-based loadModels
   API almost as easily as our previous async-marked one — the only extra step
   that’s required in this case is to type-erase our PassthroughSubject instance
   into an AnyPublisher, to prevent any other code from being able to send new
   values to our subject:
   
   extension ModelLoader {
       func modelPublisher(for urls: [URL]) -> AnyPublisher<Model, Error> {
           let subject = PassthroughSubject.emittingValues(
               from: loadModels(from: urls)
           )
           
           return subject.eraseToAnyPublisher()
       }
   }
   
   Just like that, we’ve now created two convenience APIs that make it very
   straightforward for us to make code using Swift’s concurrency system backward
   compatible with Combine — which should prove to be incredibly convenient when
   working with a code base that uses Combine to some extent.
   
   Support Swift by Sundell by checking out this sponsor:
   
   Bitrise: Easily set up fast, rock-solid continuous integration for your
   project with Bitrise. In just a few minutes, you can set up builds, tests,
   and automatic App Store and beta deployments for your project, all running in
   the cloud on every pull request and commit. Try it for free today.
   
   
   CONCLUSION
   
   Even though Swift does now have a built-in concurrency system that covers
   much of the same ground as Combine does, I think both of those two
   technologies will continue to be incredibly useful for years to come — so the
   more we can create smooth bridges between them, the better.
   
   While some developers will likely opt to completely rewrite their
   Combine-based code using Swift concurrency, the good news is that we don’t
   have to do that. With just a few convenience APIs in place, we can make it
   trivial to pass data and events between those two technologies, which in turn
   will let us keep using our Combine-based code, even as we start adopting
   async/await and the rest of Swift’s concurrency system.
   
   I hope that you found this article useful. If you did, or if you have any
   feedback, questions, or comments, then please let me know — either on Twitter
   or via email.
   
   Thanks for reading!

 * Support Swift by Sundell by checking out this sponsor:
   
   Bitrise: Easily set up fast, rock-solid continuous integration for your
   project with Bitrise. In just a few minutes, you can set up builds, tests,
   and automatic App Store and beta deployments for your project, all running in
   the cloud on every pull request and commit. Try it for free today.

 * Article
   
   
   TWO WAYS OF CAPTURING SELF STRONGLY WITHIN A CLOSURE
   
    * closures
    * language features
   
   Published on 02 Jan 2022
   
   How to use either explicit self references or a capture list to capture self
   strongly within an escaping Swift closure.

 * Podcast episode
   
   
   112: “THE 2021 SEASON FINALE”
   
    * holiday special
    * wrap-up
    * summary
   
   Published on 30 Dec 2021
   
   To wrap up the 2021 season of the show, John revisits some of the key themes
   and topics that were discussed both on the show itself, and within the Swift
   community in general, throughout the year.

 * Article
   
   
   BUILDING AN ASYNCHRONOUS SWIFTUI BUTTON
   
    * swiftui
    * concurrency
   
   Published on 22 Dec 2021
   
   How a custom SwiftUI button that’s capable of running asynchronous actions
   can be created, and how to make such a control versatile and easy to reuse
   across a project.

 * Podcast episode
   
   
   111: “CUSTOM RENDERING” WITH SPECIAL GUEST JAMES THOMSON
   
    * ui development
   
   Published on 20 Dec 2021
   
   James Thomson returns to the show to discuss the various technologies that
   enable us to render custom UIs on Apple’s platforms. From rendering views
   using Core Graphics and Core Animation, to building completely custom
   3D-based UIs using SceneKit and RealityKit.

 * Link
   
   
   NEW DISCOVER PAGE: CONCURRENCY
   
   Published on 16 Dec 2021
   
   Explore Swift’s built-in concurrency system, and how to use tools like
   async/await and actors to write concurrent code in robust and efficient ways.

 * Article
   
   
   DELAYING AN ASYNCHRONOUS SWIFT TASK
   
    * concurrency
   
   Published on 13 Dec 2021
   
   How we can use the built-in Task type to delay certain operations when using
   Swift’s new concurrency system.

 * Article
   
   
   LIGHTWEIGHT DEPENDENCY INJECTION AND UNIT TESTING USING ASYNC FUNCTIONS
   
    * concurrency
    * dependency injection
   
   Published on 09 Dec 2021
   
   Let’s explore how we could make use of Swift’s async/await capabilities to
   make our asynchronous code fully testable in a very lightweight way.

 * Podcast episode
   
   
   110: “CONCURRENCY BEYOND APP DEVELOPMENT” WITH SPECIAL GUEST TIM CONDON
   
    * concurrency
    * swift package manager
   
   Published on 06 Dec 2021
   
   Tim Condon joins John to discuss how both client and server-side Swift
   developers could utilize the new built-in concurrency system, as well as how
   distributed actors and other upcoming language features might continue to
   make Swift even more capable on the server.

 * More to read
   
   
   BROWSE ALL ARTICLES

 * More to listen to
   
   
   BROWSE ALL PODCAST EPISODES

 * More to watch
   
   
   BROWSE ALL VIDEOS

Copyright © Sundell sp. z o.o. 2022.

Built in Swift using Publish.

Twitter | RSS | Contact