I’m calling populateArray() on task. The problem is that the for loop on populateArray() continues after I navigate out of the View. How can I stop this for loop from continuing?
final class EmojisGridViewModel: ObservableObject {
@Published var emojisImageArray: [UIImage] = []
private var originalEmojisImageArray: [UIImage] = []
private let imageManager: ImageManager
private let coreDataManager: CoreDataManager
init(imageManager: ImageManager = ImageManager(),
coreDataManager: CoreDataManager = CoreDataManager.shared) {
self.imageManager = imageManager
self.coreDataManager = coreDataManager
}
func populateArray() async {
for urlString in coreDataManager.emojisDictionary.values {
if let url = URL(string: urlString),
let image = await imageManager.downloadAsyncAwait(url, type: .emoji) {
await MainActor.run {
emojisImageArray.append(image)
originalEmojisImageArray.append(image)
}
}
}
originalEmojisImageArray = emojisImageArray
}
}
struct EmojisGridView: View {
@StateObject var viewModel = EmojisGridViewModel()
private let columns = [GridItem(.adaptive(minimum: 80))]
var body: some View {
VStack {
ScrollView {
LazyVGrid(columns: columns, spacing: 20) {
ForEach(viewModel.emojisImageArray, id:\.self) { image in
Image(uiImage: image)
}
}
.padding(.horizontal)
}
}
.task {
await viewModel.populateArray()
}
}
}
>Solution :
The view cancels the task but you are calling subtasks inside and should check for the cancelation. Otherwise, they continue:
if let url = URL(string: urlString),
let image = await imageManager.downloadAsyncAwait(url, type: .emoji) {
guard !Task.isCancelled else { return } // 👈 Like this
await MainActor.run {
emojisImageArray.append(image)
originalEmojisImageArray.append(image)
}
}
You can also return the task to make it cancel automatically