This week’s article is about Swift’s function builders feature, and how it can give us some really valuable insights into how SwiftUI’s DSL operates under the hood.
In-depth articles about Swift programming techniques, language features, architectual patterns, and beyond.
This week’s article is about Swift’s function builders feature, and how it can give us some really valuable insights into how SwiftUI’s DSL operates under the hood.
Tips on how to texture SwiftUI views using tiling images, and how to ensure that such views are rendered in a smooth and predictable manner.
This week, let’s take a look at what goes into building a custom Combine publisher, and what sort of situations that might require us to do that.
A look at a few somewhat lesser-known ways in which enums can be used to solve various problems in Swift-based apps and libraries.
Let’s take a closer look at opaque return types, how they can be used both with and without SwiftUI, and how they compare to similar generic programming techniques, such as type erasure.
This week, let’s take a closer look at each of SwiftUI’s state handling property wrappers, how they relate to each other, and how they make up different parts of SwiftUI’s overall state management system.
Let’s take a look at one possible venue for learning and exploring SwiftUI without having to necessarily deploy it directly into production — by building internal tools and various prototypes.
With just a few hours to go until WWDC20 kicks off with the first ever online-only Apple keynote, I thought I’d do the same thing as I did last year, and share a few of my biggest Swift-related dreams for this upcoming WWDC.
Let’s take a look at a few key APIs and techniques that can be really useful when building custom developer tools, scripts, or other kinds of automation, in Swift.
This week, let’s explore a few different techniques for handling dynamic, polymorphic model data, in ways that still leans into Swift’s strong emphasis on type-safety.
This week’s article is about library development, and contains a few techniques and principles that can be good to keep in mind when designing and building reusable Swift libraries.
Let’s take a look at a number of techniques, patterns, and ways of structuring UI code that can help us get the very most out of Xcode’s SwiftUI-powered preview system.
This week, let’s take a look at a few techniques that can help us make our code easier to read, test and maintain, by reducing the amount of indentation within it.
Let’s take a look at a few techniques that can make it much simpler to propagate runtime errors to our users, and how employing some of those techniques could help us present richer error messages without having to add a ton of complexity within each UI implementation.
Swift’s many protocols can, in general, be split up into four main categories. Let’s go through them, and how keeping them in mind can help us write well-formed protocols that are consistent with those found in the standard library.
This week, let’s explore how we can make use of the standard library’s built-in algorithms when performing various types of queries against collections of values.
Swift enums are really powerful, but they can often be made even more capable when mixed with other kinds of Swift types — such as protocols and structs. This week, let’s take a look at a few examples of doing just that.
This week, let’s explore the topic of published properties, by reimplementing Combine’s @Published property wrapper with support for earlier versions of Apple’s operating systems.
This week, we’ll wrap up the SwiftUI layout system series by taking a look at how we can customize the layout behaviors of our views, using tools like layout priorities and alignment guides.
Let’s continue exploring the SwiftUI layout system by taking a look at a couple of more advanced techniques, such as how we can align views with dynamic dimensions and how to read a view’s geometry in order to build custom layouts.
Let’s take a look at the SwiftUI layout system by starting to build a full-screen view from scratch. Along the way, we’ll use many different techniques and APIs, which lets us explore the underlying rules of the SwiftUI layout system.
Let’s take a look at how even the smallest utility functions can have quite a big impact on the way we write code on a day-to-day basis, by making common tasks easier and preferred patterns simpler.
This week, let’s explore the topic of UI modularization in the context of SwiftUI, by taking a look at a few different techniques that can be useful in order to avoid trading Massive View Controllers for Massive Views.
This week, let’s take a look at a few tips and techniques that can help us make our types more well-defined, by splitting them up once their responsibilities have started to grow beyond the ideal scope of a single type.
The phrase “Swifty code” is often used to describe code that follows the conventions that are currently the most popular within the Swift community. But what exactly does that entail? Let’s take a look.
This week, let’s take a look at a few different ways of configuring views when using SwiftUI, and the sort of pros and cons that each of those approaches gives us in terms of code structure and flexibility.
Let’s explore two of Swift 5.2’s new features, that both give the language some really interesting capabilities from a functional programming perspective.
Let’s take a look at how we can utilize Swift’s various collection slicing APIs, and how doing so can help us boost the performance of various algorithms and functionality.
This week, let’s take a look at the various ways that Swift closures can capture the objects and values that they depend on, and how we can control those mechanics.
This week, let’s take a look at how Swift’s property wrappers work, and explore a few examples of situations in which they could be really useful.
This week, let’s take a look at various ways that we can assert that our code produces the right outcomes within our unit tests, including how we can create our own assertion functions.
A look at what goes into writing type- and protocol extensions that can be reused between different use cases and projects, and what sort of principles that can be good to keep in mind when doing that.
For the 150th weekly article on this site, and the last one before the end of the decade, let’s look back at how Swift has fundamentally changed the way apps for Apple’s platforms are built, and where things might be going from here.
Let’s take a look at one of the core aspects of object-oriented programming — initialization. What characteristics should an initializer ideally have, and what sort of techniques could be useful in order to keep our initializers simple and predictable?
This week, let’s take a look at how we can improve the internal consistency within each of our core data models, and how doing so can let us establish a much stronger foundation for our codebase as a whole.
Predicates can enable us to filter various collections in ways that are incredibly flexible. Let’s take a look at how we could construct powerful, type-safe predicates using closures, generics, and operators.
Let’s take a look at a few different ways to add plugin support to a type or library, and how doing so can enable a system to become a lot more decoupled and flexible.
This week, let’s take a look at a few core language features that enable us to design really lightweight APIs in Swift, and how we can use them to make a feature or system much more capable through the power of composition.
This week, let’s dive deep into the world of pattern matching in Swift — to take a look at how we can construct completely custom patterns, and some of the interesting techniques that we can unlock by doing so.
Let’s take a look at how combining value and reference types can unlock some really powerful capabilities, enabling us to utilize both the convenience of reference types, and the safety and limited mutability of value types.
This week, let’s take a look at a few tips and ways of thinking when it comes to approaching new tools and technologies — using the decision of whether or not to be an early adopter of SwiftUI as an example.
This week, let’s take a look at a few different ways to deploy unit testing in a more pragmatic manner — to use testing to solve immediate problems, and to enable our code to be tested without having to fundamentally change it.
When designing APIs, using default arguments can often let us strike a nice balance between flexibility and ease of use — as they let us add solid, intuitive defaults to many of the configuration options that we’ll end up providing. Let’s take a look at a few examples of how they may be used.
Let’s take a look at a few different techniques that can let us achieve a nice balance between code reuse and configurability, by building lightweight abstractions that enable us to encapsulate our configuration code.
Protocols are, without a doubt, a major part of Swift’s overall design. However, they also come with their own set of downsides and trade-offs. This week, let’s take a look at some of those characteristics, and explore a few alternative ways of abstracting code in Swift — to see how they compare to using protocols.
Let’s take a look at Foundation’s date handling APIs — how they can enable us to easily make the way we compute dates more correct, and how we can build our own lightweight abstractions on top of them to make dealing with dates in Swift a lot easier.
Swift 5.1 has now been officially released, and despite being a minor release, it contains a substantial number of changes and improvements. This week, let’s take a look at five of those features, and what kind of situations they could be useful in.
Starting with Xcode 11, the Swift Package Manager is becoming a true first class citizen within Apple’s suite of developer tools. Let’s take a look at how it can be used to manage a project’s various dependencies.
This week, let’s take a look at a few different ways that reducers can be used in Swift — ranging from transforming sequences, to accumulating asynchronous values using Apple’s new Combine framework, and beyond.
This week, let’s take a look at a few key characteristics of the most common Swift data structures, and also how we sometimes might need to venture outside the standard library to find the right data structure for our needs.
Let’s take a look at how caching can be an incredibly powerful tool in various situations, how to build an efficient and elegant caching API in Swift, and how strategically caching various values and objects can have a big impact on the overall performance of an app.
This week, let’s take a look at how subscripting works in Swift, and a few different ways to incorporate it into the way we design APIs — including some brand new capabilities that are being added in Swift 5.1.
This week, let’s take a look at convenient, but sometimes divisive language feature — computed properties — and how they can let us build really elegant convenience APIs, how to avoid accidentally hiding performance problems when deploying them, and a few different strategies for picking between a computed property and a method.
This week, let’s take a look at a technique that can let us leverage Swift’s type system to perform data validation at compile time — removing potential sources of ambiguity, and helping us preserve type safety throughout our code base — by using phantom types.
Very often we can make a big impact on the quality of our code base by improving some of its more minor details. This week, let’s take a look at one technique for doing such local improvements, by refactoring large functions into dedicated, rule-based systems.
One really interesting aspect of Swift’s overall design is how centered it is around the concept of value types. This week, let’s take a look at a few different ways in which we can make use of the semantics of value types — and how doing so could significantly improve the flexibility of our value-based code.
Deciding whether or not to generalize a piece of code to fit more than one use case can sometimes be quite tricky. This week, let’s take a look at a few key factors that can help us strike a nice balance between being able to reuse as much of our code as possible, while also avoiding making things too complicated or ambiguous in the process.
This week, let’s take a look at a few different ways that we can tweak the way Swift’s Codable API works, and how doing so can let us bridge many of the differences between our Swift types and the serialized data used to represent them — without having to fall back to implementing all of our serialization code from scratch.
While a big part of writing testable code comes down to how our dependencies are managed, how we structure and manage our testing data is often equally important. This week, let’s take a look at a few different techniques that can enable us to define such data more easily — and how that can have a big impact on how much effort that’s required to both read and manage our tests.
Even though most of our classes, structs, and other types might have initially been created to solve a very specific problem — over time, we quite often find ourselves wanting to use a highly similar version of that same type or logic, but for something entirely different. This week, let’s take a look at a technique for making that happen — that involves making certain types increasingly configurable.
This week, let’s take a look at a few techniques that we can use to prepare ourselves for undergoing major paradigm shifts when it comes to the APIs and technologies that we use to build apps — using the shift from imperative UI development with UIKit to the declarative nature of SwiftUI as an example.
SwiftUI brings a new, declarative way to build UIs for Apple’s platforms, and also pushes the Swift language itself to new limits — by making heavy use of a set of key new syntax features, that are being introduced as part of Swift 5.1, in order to provide a very DSL-like API. This week, let’s take a first look at those features and how they work.
The start of WWDC 2019 is now just hours away and, like most developers working within the Apple ecosystem, I’m getting really excited. So I thought I’d dedicate my 120th weekly Swift article to something special — dreams.
This week, let’s take a look at how well the new 3.0 version of the Swift Playgrounds app for iPad walks the balance between simplicity and power, and how some of its new features really improves the ways it can be used as a highly portable, advanced Swift development tool.
View controllers tend to play a very central part in the apps we build. This week, let’s take a look at a technique that lets us reduce the size of our view controllers by extracting their core actions, without having to introduce any additional abstractions or architectural concepts.
One major benefit of Swift’s protocol-oriented design is that it enables us to write generic code that’s compatible with a wide range of types. Let’s take a look at how we can wrap the Sequence protocol in generic containers, that’ll let us encapsulate various algorithms behind easy-to-use APIs.
Pure functions might seem like a mostly theoretical concept at first, but they have the potential to give us some very real, practical benefits — from increased reuse and testability, to more predictable code. This week, let’s take a look at how pure functions might be used in Swift — and how we can apply them to solve real problems in a very nice way.
Establishing a solid structure within a code base is often essential in order to make it easier to work with. This week, let’s take a look at a few different techniques for structuring the data that makes up our core models, and how improving that structure can have a big positive impact on the rest of our code base.
While there are a number of abstractions that we can create to be able to observe and communicate value changes — Swift comes built-in with a simple, yet powerful way to attach observations to any kind of non-lazy, stored property — appropriately named property observers.
Everyone is an API designer. While it’s easy to think of APIs as something that’s only relevant for SDKs or frameworks, it turns out that all app developers design APIs almost every single day. This week, let’s take a look at a number of tips and techniques that can be good to keep in mind when designing various APIs in Swift.
Being able to express basic values using inline literals is an essential feature in most programming languages. This week, let’s focus on string literals, by taking a take a look at the many different ways that they can be used and how we — through Swift’s highly protocol-oriented design — are able to customize the way literals are interpreted.
Arguably one of the most challenging aspects of building apps for most platforms is making sure that the UI we present to the user always remains in sync with our underlying data models, and many techniques have been invented in order to address this problem. This week, let’s take a look at one such technique, that involves binding our model values to our UI.
A situation that most Swift developers will encounter at one point or another is when some form of type erasure is needed to be able to reference a generic protocol. This week, let’s start by taking a look at what makes type erasure such an essential technique in Swift, and then explore different “flavors” of implementing it — and how each flavor comes with its own set of pros and cons.
Almost every program on the planet has to deal with strings one way or another, since text is so fundamental to how we both communicate and represent various forms of data. This week, let’s take a look at various ways to parse and extract information from strings, and how different techniques and APIs will yield a different set of trade-offs.
When writing any kind of automated tests, it can sometimes be tricky to achieve a balance between making tests run efficiently and predictably, while still exercising the right code paths under realistic conditions. This week, let’s take a look at one way to achieve such a balance, by verifying the integration between multiple code units.
The UserDefaults API can at first glance appear to be somewhat limited. However, it turns out that the power of UserDefaults extends far beyond simply storing and loading basic value types. This week, let’s take a look at what some of that power comes from, and how we can appropriately make use of it in the apps that we build.
One really elegant aspect of Swift’s design is how it manages to hide much of its power behind much simpler programming constructs. Pattern matching is one source of that power, especially considering how it’s integrated into many different aspects of the language.
One way to make a code base easier to navigate, while still maintaining a solid overall structure, is to inline functionality whenever two pieces of code are heavily related. This week, let’s take a look at how that can be done using inline types and functions, and how — when tactically deployed in the right situations — it can make our code a bit easier to follow.
Reflection is a common programming language feature that enables us to inspect, and work with, the members of a type — dynamically, at runtime. That may seem at odds with Swift’s heavy focus on compile-time validation — but this week, let’s take a look at when reflection can come in handy, and how it can let us make our code a bit more dynamic.
Concurrent code can come in many different shapes and forms. Depending on what we’re trying to achieve, the abstraction that’ll prove to be the best fit might vary quite a lot from use case to use case. One such abstraction is Tasks, and this week, let’s take a look at some scenarios in which they can become really useful.
When writing automated tests, many of us have a tendency to focus on verifying that our code behaves correctly under ideal conditions, but we should really also test how our code behaves when something goes wrong. This week, let’s take a look at how unit tests can be used to verify the correctness of our code’s various failure states.
When using syntactic sugar, what we ideally want is to be able to strike a nice balance between low verbosity and clarity, and this week, let’s take a look at a few different ways that type aliases can enable us to do just that.
We might not realize it, but most of us share code with other people every single day. However, sharing code in a way that’s clear and effective can be quite difficult, so for the 100th weekly article on this site — let’s take a look at what goes into sharing code in a nice way, and some techniques that we can employ to make any code that we share easier to understand.
This week, let's take a look at a way of writing networking code that utilizes Apple's built-in URLSession API, while augmenting it using Futures & Promises, as well as several functional programming concepts.
While 2018 has been the first year since Swift was introduced in 2014 without a new major release — it has still proven to be quite a transformative year for the language, its usage, and the community as a whole. Let’s take a quick look back at 2018, at what has been some of the most popular articles on this site, as well as general trends in the development and usage of Swift.
Designed to be an easy way to quickly prototype Swift code, to learn the language, or to explore the standard library and Apple’s SDKs — Swift playgrounds have become an integral part of many developers’ daily workflows. This week, let’s take a look at some tips and tricks that can make working with Swift playgrounds, both in Xcode and on the iPad, much more productive.
One of the most challenging decisions that all programmers have to make on an ongoing basis is when to generalize a solution versus just keeping it tied to a specific use case. This week, let’s take a look at a way of building UIs that might allow us to strike a nice balance between those two approaches, using slots.
How we manage the control flow within the apps and systems that we work on can have a huge impact on everything from how fast our code executes, to how easy it is to debug. This week, let's take a look at how we can use Swift's built-in error throwing and handling model to make our control flow more clear and predictable.
When getting started with unit testing, it usually doesn't take long to realize that some form of mocking is needed. Although mocking will most likely remain essential for many types of testing, this week, let's take a look at a few different ways to write mock-free unit tests in Swift.
One of the most important roles of any software architecture is to make the relationships between the various objects and values within an application as clear as possible. This week, let's take a look at how we can do that by using the type system to set up locks and keys to get a stronger, compile-time guarantee that the intended flow of our app will remain intact at runtime.
A really elegant aspect of Swift's take on optionals is that they're largely implemented using the type system - since all optional values are actually represented using an enum under the hood. That gives us some interesting capabilities, since we can extend that enum to add our own convenience APIs and other kinds of functionality. This week, let's take a look at how to do just that.
Whether or not you believe that the iPad is the future of computing, it does bring a ton of interesting new features and capabilities to the table, especially with the latest release of the Pro version. This week, let’s take a look at how we as third-party developers can take advantage of some of those capabilities to build interesting new features for our iOS apps.
A race condition is what happens when the expected completion order of a sequence of operations becomes unpredictable, causing our program logic to end up in an undefined state. This week, let's take a look at a common scenario that can cause race conditions, possible ways to avoid them - and how we can make our code more robust and predictable in the process.
Swift keeps gaining more and more features that are more dynamic in nature, while still retaining its focus on type safe code. This week, let’s take a look at how key paths in Swift work, and some of the cool and powerful things they can let us do.
Protocols continue to be an integral part of Swift, both in terms of how the language itself is designed, and also in how the standard library is structured. This week, let's take a look at how we can use protocols to create multiple levels of abstraction, and increasingly specialize them to become more and more specific to each use case.
A DSL, short for Domain Specific Language, can be explained as a special kind of API that focuses on providing a simple syntax that's tailored to working within a specific domain. Swift's type inference and overloading capabilities also make it a really great language to build DSLs in - and this week, let's do just that.
This week, let's take a look at various techniques for working with URLs in Swift, how to make our URL construction code more robust, and how different kinds of URLs might warrant different approaches.
View models attempt to make it easier to write and maintain view-specific logic, by introducing dedicated types for it. This week, let’s take a look at a few different ways that various flavors of view models can be implemented in Swift.
Asynchronous code is essential to providing a good user experience, but can at times be really tricky to write, debug and especially test. This week, let's explore how we can make our asynchronous tests much simpler, inspired by the async/await programming paradigm.
This week, let's take a look at how we can implement data sources for table and collection views in a more reusable manner, and how doing so can let us make our list-based UI code more composable and easier to work with.
This week, let’s take a look at how we can use the presenter pattern to move some code normally contained within view controllers - specifically related to the presentation of additional UIs - into separate, dedicated types, to improve our separation of concerns.
This week, let's take a look at how we can be inspired by the functional programming world to improve the structure and robustness of our Swift code - this time focusing on using functions that return objects and values as early as possible.
With each new release, Swift keeps getting better and better at creating compiler-generated implementations of common boilerplate. One such new feature in Swift 4.2 is the new CaseIterable protocol - that enables us to tell the compiler to automatically synthesize an allCases collection for any RawRepresentable enum. This week, let's take a look at some examples of scenarios in which this new feature can come very much in handy.
Proper encapsulation of logic is one of the most important things when it comes to building well-architected apps and systems. This week, let's take a look at how we can better incapsulate our model layer's logic by using model controllers.
Adding new features to an app or framework often involves adding new arguments to existing functions. While most such changes may seem trivial at first, if we're not careful, we could - over time - end up with functions that are a bit unclear and cumbersome to use. This week, let's take a look at how to deal with such functions, and how they often can be simplified by reducing the number of arguments they accept.
Type inference is a key feature of the Swift type system and plays a big part in the syntax of the language - making it less verbose by eliminating the need for manual type annotations where the compiler itself can infer the types of various values.
One thing that almost all apps and frameworks have in common is that they tend to grow in both size and complexity as time passes. As a project grows it becomes more and more important to maintain a solid and consistent structure, but at the same time it also becomes increasingly difficult to do so.
Adding new features to existing code can be really challenging - especially if that code is heavily used throughout one or many projects. Backward compatibility can in many ways help us make such changes in a much smoother fashion, so this week, let's take a look at a few different techniques that can help us make changes to our code base fully backward compatible.
Being able to use unit testing in a productive way often requires the various parts of an app to be written with testability in mind, which isn't always the case. This week, let's take a look at a few different refactoring techniques that can help us make non-testable code much easier to test.
While subclassing is not universally bad, avoiding it can in many situations leave us with simpler code that is easier to change and reuse. This week, let's take a look at a few different techniques that can help us write subclass-free view controllers, and how it can help us avoid the Massive View Controller problem.
View controller containment has been an essential part of UIKit ever since the early days of the iPhone. This week, let's take a look at how we can build our own container view controllers, and how doing so can help us make parts of our UI code more modular and easier to manage.
One of the most important aspects of any app's architecture is how data and models are dealt with. This week, let's take a look at a few different techniques that can help us make code dealing with mutable models a bit more predictable.
This week, let's explore various versions of the commonly used Result type (including the implementation included in the Swift 5 version of the standard library), and some of the cool things it lets us do when combined with some of Swift's language features.
When writing tests for any application, it's always important to consider what the debugging experience will be like when they eventually start failing. This week, let's take a look at a few different scenarios, and how we - with just a few subtle tweaks - can make our tests a lot easier to debug.
Most objects require some form of setup before they're ready to be used in an app. While it’s very common to create subclasses for that purpose, this week, let's take a look at an alternative approach to writing setup code that doesn't require any form of subclassing - by using static factory methods.
When and how to write documentation and code comments tends to be something that causes a lot of debate among developers. This week, let's take a look at a few simple tips and tricks that can let us write code that is more self-documenting - code that makes the underlying intent and details more clear, simply by the way it's structured and how it's written.
While launch arguments are probably most commonly used as input to command line tools - this week, let's take a look at how we can also use the power of launch arguments when working on, debugging, and testing an iOS app.
In most code bases, we need a way to uniquely identify certain values and objects. This week, let’s take a look at how we can create type-safe identifiers that enable us to write more robust model handling code.
One big challenge that most Swift developers face from time to time, is how to deal with Massive View Controllers, both in terms of scope and number of lines of code. This week, let’s take a look at how such view controllers can be broken up using Logic Controllers.
The delegate pattern has long been very prominent on Apple's platforms, and used for everything from handling table view events using UITableViewDelegate, to modifying cache behavior using NSCacheDelegate. This week, let's take a look at a few ways to implement the delegate pattern, along with their pros and cons.
This week, we'll continue exploring various ways to implement the observer pattern in Swift. Last week we took a look at using the NotificationCenter API and observation protocols to enable an AudioPlayer to be observed, and this week we'll do the same thing but instead focusing on multiple closure-based techniques.
Often when building apps, we find ourselves in situations when we need to set up a one-to-many relationship between objects. In such situations, it's very common to want to add some way for certain objects to be observed. We'll start by taking a look at two such observation techniques this week, and then next week we'll continue with a couple of other ones.
Like many abstractions and patterns in programming, the goal of the builder pattern is to reduce the need to keep mutable state - resulting in objects that are simpler and generally more predictable. By enabling objects to become stateless, they are usually much easier to test and debug - since their logic consists only of "pure" input and output.
This week, let's take a look at Swift 4.1's new Conditional Conformances feature, and how it enables us to design code in a much more recursive fashion, making it more flexible while also reducing duplication. We'll take a look at both a simple and more advanced example, and how the standard library uses this new feature.
When developing new features for an app, it can be really useful to have some form of mechanism to gradually roll out new implementations and functionality. Feature flags can act as such a mechanism, since they allow us to gate parts of our code base off under certain conditions, either at compile time or at runtime.
Something that tends to be particularly tricky when it comes to finding a good balance between convenience and maintainability, is when setting up relationships between the view layer and the model layer. This week, let's take a look at a few different ways that we can decouple our UI code from our model code, and some of the benefits of doing so.
One really interesting feature of Swift is the ability to create lightweight value containers using tuples. The concept is quite simple - tuples let us easily group together any number of objects or values without having to create a new type. But even though it's a simple concept, it opens up some really interesting opportunities, both in terms of API design and when structuring code.
Although Set is one of those core data structures that you see in almost every programming language, it sometimes get a bit overlooked. This week, let's take a look at a few different examples of when using a set can lead to more predictable performance and simpler code, as well as some of Swift's Set type's lesser known - yet very powerful - features.
One of the biggest challenges when working on a continuously evolving code base is to keep things nicely encapsulated. Adding new capabilities without leaking abstractions can be really tricky. This week, let's take a look at a few techniques that can let us define more clearly encapsulated APIs in different situations.
Every app that doesn't only consist of one single UI needs some form of navigation - to enable users to move between different screens and to display information or react to events. This week, let's take a look at a few different options for dealing with navigation in Swift apps, focusing on iOS this time.
When starting to work with tests, there's one problem in particular that almost every developer runs into - how to test asynchronous code. While we've touched on this subject before, this week, let's focus in on a few different techniques that can help make testing asynchronous code a lot easier.
Few Swift features cause as much heated debate as the use of custom operators. While some people find them really useful in order to reduce code verbosity, others think that they should be avoided completely. This week, let's take a look at a few situations that custom operators could be used in, and some of the pros and cons of using them.
Composition is a super useful technique that lets us share code between multiple types in a more decoupled fashion. It's often posed as an alternative to subclassing, with phrases like "Composition over inheritance" - which is the idea of composing functionality from multiple individual pieces, rather than relying on an inheritance tree. This week, let's take a look at a few situations in which composition can be used with structs, classes and enums in Swift.
Almost every Swift program uses collections in one way or another. Whether it's to store values to be displayed in some form of list, to keep track of observers, or caching data - collections are everywhere. This week, let's take a look at some of the standard library APIs that let us easily transform collections in a very functional way.
Mocking is a key technique when it comes to writing unit tests in pretty much any language. Whether we're testing networking code, code relying on hardware sensors like the accelerometer, or code using system APIs like location services - mocking can enable us to write tests a lot easier, and run them faster in a more predictable way.
Languages that support first class functions enable us to use functions and methods just like any other object or value. We can pass them as arguments, save them in properties or return them from another function. In order words, the language treats functions as "first class citizens".
Before we dive into new topics and new formats in 2018, I want to dedicate this week's post to highlighting some of the most popular posts from this year, as well as share some overarching themes and patterns that I've noticed among them.
Separation of concerns is a core principle when it comes to designing architectures and systems. However, even though it's a principle most programmers learn about early in their career, it's not always easy to apply in practice. This week, let's take a look at how to more easily separate the concerns of various types in Swift, using protocols.
Just like with most programming techniques, there are multiple "flavors" of dependency injection - each with its own pros and cons. This week, let's take a look at three such flavors and how they can be used in Swift.
UI testing can be a really useful tool in order to assure that the key user interactions of the apps we build will keep working as expected. This week, let's take a look at how to add UI tests to verify an app's analytics code, and how it can be a great way to quickly gain a broad UI testing coverage.
Gathering some form of analytics from users can be cruicial when building, iterating on and improving a product. Learning how users use our app in real-life situations can sometimes be really surprising and take its development in new directions. This week, let's take a look at how an analytics system can be architected and implemented based on enums.
Managing memory and avoiding leaks is a crucial part of building any kind of program. This week, let's take a look at how we can set up unit tests to both help us identify memory leaks, and also make it easier to avoid common mistakes that could end up causing leaks in the future.
A very common problem when building apps for Apple's platforms is where to put common functionality that's used by many different view controllers. Rather than using a BaseViewController or relying on inheritance in some other way, let's take a look at how we can structure common functionality as child view controllers that can be used as plugins.
While force unwrapping is an important feature, it also circumvents parts of what makes Swift so great. However, dealing with optionals and unknown types in a safe way can require quite a lot of code, so the question is whether we want to do all of that additional work when writing tests as well?
Dependency injection is an essential tool when it comes to making code more testable. This week, let's take a look at a dependency injection technique that lets us enable testability without forcing us to write massive initializers or complicated dependency management code.
Handling asynchronous code in a way that is predictable, readable and easy to debug can be really challenging. This week, let's take a look at a technique that can make managing asynchronous calls a bit simpler and less error prone - using tokens.
Even though closures are very widely used, there's a lot of behaviors and caveats to keep in mind when using them. This week, let's take a closer look at closures, how capturing works and some techniques that can make handling them easier.
Open source is incredibly important for our industry, and it's big reason why I love the Swift community so much. This week I thought I’d try to sum up most of my tips and tricks on how to publish a new Swift open source project.
There seems to almost be a consensus in the community that singletons are "bad", but at the same time both Apple and third party Swift developers keep using them both internally within apps and in shared frameworks. This week, let's take a look at exactly what the problems are with using singletons, and explore some techniques that can be used to avoid them.
Using generic type constraints, we are able to add new APIs and behaviors to a type only under a certain set of constraints. This week, let's take a look at some techniques and patterns that are made possible because of type constraints, and how they can be used in practice.
While switch statements are hardly something that was invented as part of Swift, they are made a lot more powerful when combined with Swift's type system. This week - let's go further beyond switching on single enum values and take a look at more of the powerful capabilities that switch statements offer in Swift.
When creating collections of objects or values in Swift, we usually use data structures provided by the standard library - such as Array, Dictionary and Set. While those three cover most use cases, sometimes creating a custom wrapper collection can enable us to make our code more predictable and less prone to errors.
Assertions are not only an essential tool when writing tests - they're also super useful in order to write more predictable and easier to debug code. This week, let's look deeper into assertions, how they work, and how we can implement our own assert functions for performing various checks.
Shared state is a really common source of bugs in most apps. It's what happens when you (accidentally or by design) have multiple parts of a system that rely on the same mutable state. This week, let's take a look at how shared state can be avoided in many situations, by using the factory pattern to create clearly separated instances that each manage their own state.
In this new (non-consecutive) series of posts - "Core Animation Gems" - we'll take a closer look at some of Core Animation's less widely known features and APIs, and how they can be used to solve problems related to animation and rendering in a nice way. This week, let's kick it off with the first one - CAReplicatorLayer.
An important part of maintaining any app, framework, or system is dealing with legacy code. This week, let's take a look at a technique for dealing with legacy code that lets us replace a problematic system class-by-class, rather than having to do it all at once.
Let's take a look at Futures and Promises, a really popular abstraction for making asynchronous code easier to manage, by writing an implementation from scratch.
Flakiness is what happens when tests don't run consistently, when different circumstances produce different results. This week, let's take a look at some easy-to-apply tips and tricks that can help reduce flakiness, and make our tests more predictable within any environment.
This week, let's finish building the animation framework that we started in last week's post! We'll continue building a declarative animation API, that will now also support sequencing of animations performed on multiple views.
This week, let's take a look at how we can make view-based animations (animating individual UIViews, like buttons and labels) on iOS easier to handle - by building a simple framework that will enable us to express animations in a very declarative, composable way.
We often encounter situations in which we need to find a way to store objects based on some concept of identity. Whether it's in a cache, storing representations of objects on disk, or simply using a dictionary - we often need to find ways to uniquely identify the objects that we deal with. Let's take a look at a few such ways.
Almost all modern apps use JSON in one way or another. Whether it's for configurations, to store local data or to download information over the network - JSON is everywhere. This week, let's take a look at how we can set up our JSON mapping tests to make them a lot more robust and future proof, and how we can use them to perform end-to-end testing.
One of the hardest parts of building apps is deciding how to model state. Code managing state is also a very common source of bugs, when parts of our app might end up in a state we didn't expect. This week, let's take a look at some techniques that can make it easier to write code that handles and reacts to state changes.
Animations are a great way to explain the functionality of our apps through motion, and to delight our users. Adding animations in the right places can really make a UI look a lot more polished and nice. This week, let's take a look at how SpriteKit can be a great tool for creating certain kinds of animations.
Swift playgrounds are awesome for things like trying out new frameworks and exploring new language features. The instant feedback they give us can really provide a huge productivity boost and enable us to try out new ideas and solutions quickly. This week, let’s take a look at how Swift playgrounds can also be used for writing unit tests.
Swift 4 introduces a new, refined string API that is easier to use, more powerful, and gives the programmer more control in terms of memory management. This week, let’s take a look at how it is to work with strings in Swift 4, and how we can take advantage of the new, improved API in various situations.
Grand Central Dispatch is one of those fundamental technologies that most Swift developers have used countless times. This week, let’s go beyond async and take a look at some situations where GCD can be really useful, and how it can provide simpler (and more “Swifty”) options to many other Foundation APIs.
Swift’s @autoclosure attribute enables us to define an argument that automatically gets wrapped in a closure. It’s primarily used to defer execution of a (potentially expensive) expression to when it’s actually needed, rather than doing it directly when the argument is passed.
UI testing can be a great way to ensure that our key UI interactions keep working as we’re adding new features, or when refactoring our app’s codebase. It can also be a really nice way to automate repetitive tasks when working on UI code. Let’s take a look at how to get started.
Lazy properties allow you to create certain parts of a Swift type when needed, rather than doing it as part of its initialization process. This can be useful in order to avoid optionals, or to improve performance when certain properties might be expensive to create. This week, let’s take a look at a few ways to define lazy properties in Swift, and how different techniques are useful in different situations.
This week, let’s take a look at how we can use Continuous Integration (or CI) to establish a smooth and nice workflow for our team when working on a Swift project.
One major focus of Swift is compile time safety — enabling us as developers to easily focus on writing code that is more predictable and less prone to runtime errors. However, sometimes things do fail for various reasons — so this week, let’s take a look at how we can handle such failures appropriately, and what tools we have at our disposal for doing so.
A lot of code that we write relies on the current date in some way. Let's take a look at how to test such code in a fast and predictable way, without having to invent a lot of infrastructure or resort to hacky solutions like swizzling the system date.
In my first ever tutorial, I'll provide a step-by-step guide for building a command line tool using the Swift Package Manager, sharing some learnings from when I built Marathon.
Even though Optionals are one of the most important features of Swift, sometimes they can put you in somewhat of a tight spot. Let's take a look at how to avoid those situations, and how to deal with non-optional optionals in a nice way.
While Swift does not yet feature a dedicated namespace keyword, it does support nesting types within others. Let’s take a look at how using such nested types can help us improve the structure of our code.
Most apps written for any of Apple’s platforms rely on APIs that are singleton-based. From UIScreen to UIApplication to NSDate, static APIs are everywhere in Foundation, UIKit and AppKit. In this article I'll go through 3 steps to easily test code that uses such APIs.
Dependency injection is a great technique for decoupling code and making it easier to test. In this article, let’s take a look at how functions can be used for simple dependency injection.
One thing that can sometimes be quite cumbersome when working with Swift on a larger scale is how long it can currently take to compile. In this article, let's take a look at some practical tips and tricks that I’ve found can make compile times faster.
How to use custom, lazily evaluated sequences in Swift to improve performance and enable you to deal with larger datasets, such as entries in a database.
How type erasure can be implemented using closures, and how it can help you work around using protocols with self or associated type requirements.
I’d like to share a technique that I’ve come to find quite useful when using Swift’s do, try, catch error handling model — to limit the amount of errors that can be thrown from a given API call.