In designing the async/await construct, Apple is hoping to increase the readability, and thus maintainability, of implementing concurrency/parallelism in Swift. What I see in it are attempts:
to make asynchronous/parallel code almost look like synchronous/sequential code; and,
to make asynchronous/parallel code much more semantically clear (more readable, less verbose, compact, doing what it says).
These are laudable and ambitious goals, but I’d say Apple’s heading in the right direction. I’m glad because I write a lot of asynchronous code to keep my apps responsive — to create the best possible user experience for my customers. I have a feeling that most of you write a lot of concurrent code, too.
We’ll walk through how to use async/await in detail, but I will limit my discussion to it. You need to understand async/await before trying to use Swift’s other new concurrency features, like actors, continuations, the AsyncSequence protocol, the TaskGroup generic structure, task cancellation, and a few other concepts.
Those of you who’ve used Objective-C and Swift for any meaningful length of time must be familiar with the self property of structs and classes. I’m not sure how many are aware of the Self “type” (sometimes called a “requirement”). I would be very interested in knowing how many understand the difference between self and Self. I’m talking about self with lower-case “s,” which I’ll call “small self” herein. It’s pretty well documented. Similarly, Self with an upper-case “S,” is what I’ll call “tall self” herein. It’s not very well documented.
In this tutorial, I’ll show you how to track down memory leaks within Xcode via the Memory Graph Debugger, new since Xcode 8. This is a powerful visual tool and doesn’t require you to step out of Xcode and start the Leaks Instrument. Once we identify some memory leaks, I’ll show you how to plug those leaks by using the Swift language’s weak and unowned qualifiers, and talk about the differences between the two qualifiers.
I recently discussed iOS memory management and memory leaks that occur when using reference semantics and reference types (classes) in my tutorials on “Swift 4 memory management via ARC for reference types (classes)” and “Fixing memory leaks — strong reference cycles — in Swift 4.” After reading these articles, you should understand how easy it is to inadvertently encode and introduce a strong reference cycle into your Swift 4 code and thus end up with a memory leak. You should also understand how generally straightforward it is to fix such a memory leak. My sample code in both tutorials was didactic. What about real-world projects with hundreds of thousands or millions of lines of code? Suppose that you’ve heard reports of diminished app performance, low memory warnings, or just plain app crashes. Finding memory leaks in your code is quite cumbersome when trying to debug via rote inspection, setting breakpoints, adding logging statements, etc.
Design patterns are very important tools for iOS developers to keep in their software engineering arsenals. These patterns, along with several other best practices I’ll mention below, help developers to create reliable and maintainable apps. In other words, design patterns help in managing software complexity. In this tutorial, I’ll introduce you to the “Model-View-ViewModel” or “MVVM” design pattern. For a historical and pragmatic perspective, I’ll compare the very well-known “Model-View-Controller” or “MVC” design pattern, long favored by many iOS developers, to MVVM, which has steadily been gaining traction among the same group of developers.
In order to help you understand these design patterns, I’ll walk you through the design and coding of my app shown here:
Today, I’ll show you how to use Swift 4 and the Grand Central Dispatch (GCD) application programming interface (API) to implement the execution of (multiple) tasks in the background, i.e., parallel/concurrent execution of tasks on a multicore CPU. I’ve built a sample app that gives you two options: 1) synchronous execution of tasks in the background and 2) asynchronous execution of tasks in the background. All my Swift 4 code from this article, part of an Xcode 9 project which builds a fully-functional working sample app, is available for download here. Join me in: reviewing concurrent programming concepts; reviewing my concurrent Swift 4 code; and, examining videos of my app in action, videos of console output from my app, and the console output text itself. I’ll even show you how to graphically visualize my app’s CPU and thread usage with Xcode’s Debug Navigator.
This is a look at the app — a snapshot — after all images have finished downloading asynchronously in the background:
Here’s a video of the app downloading images asynchronously in the background:
Press the play button if you missed the first showing
I’m going to introduce you to iOS concurrency with simple Swift 4 code that uses an API based on the Operation abstract class. In more complex scenarios, you would subclass and customize Operation, but iOS provides the built-in BlockOperation subclass of Operation which we’ll use here. I’ll review the tenets of concurrency, emphasize why it is necessary in almost all apps, explain the basic infrastructure of Operation, compare it to Grand Central Dispatch (GCD), and then walk you through the Swift 4 code I wrote to implement concurrency in a real-live app based on BlockOperation. I’ll even show you how to graphically visualize your app’s CPU and thread usage with Xcode’s Debug Navigator. Here’s the app that we’ll build together:
Press the play button if you missed the first showing
We now live in the day and age of writing apps that can run on devices with CPUs that have multiple cores. We can go way beyond the notion of “multitasking” as a bunch of processes vying for a “timeslice” of the CPU. We can literally run processes simultaneously on different cores. As iOS developers, it is vitally important that we understand the concept of concurrency. Why?
Today, we’ll finish our discussion of the benefits of using Objective-C blocks and Swift closures by writing code to define and use a closure in Swift 3. For the full background on this topic, please read my last post entitled “Make blocks (closures) your friend (Objective-C and Swift 3).” Let’s plunge into Swift 3: