Let’s look at an example stream which begins with an array of Entity values. Our goal is to transform each value in the array of Entity, into a new value of EntityDisplay which is more suitable for rendering in the UI.
struct Entity {
let id: String
let name: String
let description: String
let date: Date
}
struct DisplayEntity {
let entity: Entity
var text: String {
return "\(entity.name): \(entity.description)"
}
var date: String {
let formatter = DateFormatter()
formatter.dateStyle = .short
formatter.timeStyle = .short
return formatter.string(from: entity.date)
}
}
We’ll use a helper function to create some entities to work with:
func createEntities() -> [Entity] {
return (0..<5).map {
let id = $0 + 1
return Entity(id: "\(id)", name: "Entity \(id)", description: "Description \(id)", date: Date())
}
}
Once we have a publisher for our array of Entity values, mapping to an array of EntityDisplay values requires 2 simple steps.
- Use the Combine map operator to transform the [Entity] publisher to a publisher of a new value (in our case this will be [EntityDisplay]).
- Inside of this transform closure, we use the standard Swift Collection map method on the [Entity] array itself, mapping each value from Entity to DisplayEntity.
Just(createEntities())
.map { $0.map { DisplayEntity(entity: $0) } }
.sink { print($0) }
.store(in: &subscriptions)
It’s as simple as that!
We can take this a step further, by creating an extension on Publisher to encapsulate this ‘2 step’ mapping. Shout out to @danielt1263 on the RxSwift slack group for this great snippet below.
extension Publisher where Output: Sequence {
public func mapArray<Input, Out>(_ transform: @escaping (Input) -> Out) -> Publishers.Map<Self, [Out]> where Output.Element == Input {
map { $0.map { transform($0) } }
}
}
Using this extension, we can make our mapping look a little more zen, like so:
Just(createEntities())
.mapArray { DisplayEntity(entity: $0) }
.sink { print($0) }
.store(in: &subscriptions)
You can grab all of the code above from this gist. There will be many more posts on reactive programming in Combine coming soon, so stay tuned by subscribing below 🚀.