How to Use Type Erasure in Swift with a Real Example

Oleksandr Kaledin
3 min readNov 6, 2023

--

Photo by Amza Andrei on Unsplash

Introduction

Swift is a versatile and powerful programming language, but it can be challenging to work with heterogeneous collections of objects with different types. Type erasure is a technique in Swift that allows you to abstract away the specific type of an object and work with it more generically. In this article, we’ll explore how to use type erasure in Swift with a real-world example.

Understanding Type Erasure

Type erasure is a technique in Swift that allows you to hide the specific type of an object and expose it as a more abstract type. This can be especially useful when dealing with collections of objects with different types, as it allows you to treat them all as instances of a common, abstract type.

One of the most common use cases for type erasure is when working with protocols and generics. You can use type erasure to wrap an object that conforms to a protocol and expose it as a more generic type, making it easier to work with heterogeneous collections of objects.

Real-World Example

Let’s illustrate the concept of type erasure with a real-world example. Imagine building an app fetching data from various sources, such as a local database and a remote API. You want to create a generic data source that can handle data from any source and use type erasure to achieve this.

  1. Define the Data Source Protocol:
protocol DataSource {
associatedtype DataType
func fetchData(completion: @escaping (Result<DataType, Error>) -> Void)
}

In this example, we define a DataSource protocol with an associated type DataType. The fetchData function retrieves data of the associated type and calls a completion handler with the result.

Implement Concrete Data Sources:

Next, you create concrete data sources that conform to the DataSource protocol. For instance, you might have a LocalDataSource and a RemoteDataSource:

struct LocalDataSource<T>: DataSource {
typealias DataType = T
// Implement fetchData for local data source
}

struct RemoteDataSource<T>: DataSource {
typealias DataType = T
// Implement fetchData for remote data source
}

Create a Type-Erased Wrapper:

Now, you create a type-erased wrapper that hides the specific data source type but still conforms to the DataSource protocol. This allows you to work with a collection of data sources without caring about their concrete types.

struct AnyDataSource<T>: DataSource {
typealias DataType = T

private let _fetchData: (@escaping (Result<DataType, Error>) -> Void) -> Void

init<ConcreteDataSource: DataSource>(_ concreteDataSource: ConcreteDataSource) where ConcreteDataSource.DataType == T {
self._fetchData = concreteDataSource.fetchData
}

func fetchData(completion: @escaping (Result<DataType, Error>) -> Void) {
_fetchData(completion)
}
}

In the AnyDataSource struct, we store a closure _fetchData that delegates the fetchData call to the concrete data source. This way, we can wrap any data source and expose it as an AnyDataSource without revealing its specific type.

Using Type Erasure in Practice:

Now you can use the type-erased data source in your app:

let localDataSource = LocalDataSource<Int>()
let remoteDataSource = RemoteDataSource<String>()

let anyLocalDataSource = AnyDataSource(localDataSource)
let anyRemoteDataSource = AnyDataSource(remoteDataSource)

let dataSources: [AnyDataSource<Any>] = [anyLocalDataSource, anyRemoteDataSource]

for dataSource in dataSources {
dataSource.fetchData { result in
// Handle the result without knowing the concrete data source type
}
}

In this example, you create specific data sources, wrap them using AnyDataSource, and then work with them in a generic collection. This demonstrates the power of type erasure in Swift for managing heterogeneous data sources.

Conclusion

Type erasure is a valuable technique in Swift for abstracting away specific types and working with more generic interfaces. It is particularly useful when dealing with collections of objects of different types. In this article, we’ve explored how to use type erasure with a real-world example of creating a generic data source that can handle data from various sources. By following this approach, you can write more flexible and maintainable code in your Swift applications.

--

--

Oleksandr Kaledin

iOS App Developer with 2+ years' experience. Expert in Swift, Xcode, and tech writing.