Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
A SwiftUi GridView to demonstrate multiple downloads using Combine.
import Foundation
import Combine
import SwiftUI
import UIKit
struct GridView: View {
@ObservedObject
var vm = GridViewModel()
let rows: Int = 25
let columns: Int = 4
let padding: CGFloat = 10
var body: some View {
GeometryReader { proxy in
ScrollView {
ForEach(0..<self.rows, id: \.self) { r in
HStack(spacing: self.padding) {
ForEach(0 ..< self.columns, id: \.self) { c in
ItemView(image: self.vm.images[r*self.columns + c],
columns: self.columns,
width: proxy.size.width - (CGFloat(self.columns) * self.padding + self.padding))
}
}
}
}
}
.padding(padding)
.onAppear {
self.vm.fetch(n: 100)
}
}
}
struct ItemView: View {
let image: Image
let columns: Int
let width: CGFloat
var body: some View {
self.image
.resizable()
.aspectRatio(contentMode: .fit)
.frame(width: width / CGFloat(self.columns), height: width / CGFloat(self.columns))
.border(Color.gray)
.cornerRadius(5)
}
}
extension Image {
static var `default` = Image(systemName: "photo")
}
class GridViewModel: ObservableObject {
private var cancellableSet: Set<AnyCancellable> = []
@Published
private (set) var images = Array(repeating: Image.default, count: 100)
func fetch(n: Int) {
let arrayOfPublishers = (0...n).map { _ in
fetchImage()
}
Publishers.Sequence(sequence: arrayOfPublishers)
.flatMap{ $0 }
.collect()
.receive(on: RunLoop.main)
.sink {
self.images = $0
}
.store(in: &cancellableSet)
}
private func fetchImage() -> AnyPublisher<Image, Never> {
let url = URL(string: "https://picsum.photos/80")!
return URLSession.shared.dataTaskPublisher(for: url)
.map {
guard let uiImage = UIImage(data: $0.data) else {
return Image.default
}
return Image(uiImage: uiImage)
}
.replaceError(with: Image.default)
.eraseToAnyPublisher()
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.