Skip to content

Commit

Permalink
Extract Event/AsyncContext handling in a separate method
Browse files Browse the repository at this point in the history
  • Loading branch information
kean committed Apr 28, 2024
1 parent 13f665a commit ec92d73
Show file tree
Hide file tree
Showing 2 changed files with 21 additions and 5 deletions.
21 changes: 16 additions & 5 deletions Sources/Nuke/ImageTask.swift
Original file line number Diff line number Diff line change
Expand Up @@ -207,11 +207,26 @@ public final class ImageTask: Hashable, CustomStringConvertible, @unchecked Send
// MARK: Events

func process(_ event: Event) {
switch event {
case .progress(let progress):
currentProgress = progress
case .finished:
// TODO: do we need to check state?
_ = setState(.completed)
default:
break
}

let context = sync { _context }
process(event, in: context)
onEvent?(event, self)
pipeline?.imageTask(self, didProcessEvent: event)
}

private func process(_ event: Event, in context: AsyncContext) {
context.events?.1.yield(event)
switch event {
case .progress(let progress):
currentProgress = progress
context.progress?.1.yield(progress)
case .preview(let response):
context.stream?.1.yield(response)
Expand All @@ -221,16 +236,12 @@ public final class ImageTask: Hashable, CustomStringConvertible, @unchecked Send
context.stream?.1.finish(throwing: CancellationError())
continuation?.resume(throwing: CancellationError())
case .finished(let result):
_ = setState(.completed)
let result = result.mapError { $0 as Error }
context.events?.1.finish()
context.progress?.1.finish()
context.stream?.1.yield(with: result)
continuation?.resume(with: result)
}

onEvent?(event, self)
pipeline?.imageTask(self, didProcessEvent: event)
}

/// An event produced during the runetime of the task.
Expand Down
5 changes: 5 additions & 0 deletions Sources/Nuke/Pipeline/ImagePipeline.swift
Original file line number Diff line number Diff line change
Expand Up @@ -288,6 +288,7 @@ public final class ImagePipeline: @unchecked Sendable {
private func makeStartedImageTask(with request: ImageRequest, isDataTask: Bool = false) -> ImageTask {
let task = ImageTask(taskId: nextTaskId, request: request, isDataTask: isDataTask)
task.pipeline = self
// TODO: we've added a dealy to startImageTask and that can be a problem
task.task = Task {
try await withUnsafeThrowingContinuation { continuation in
queue.async {
Expand All @@ -305,6 +306,10 @@ public final class ImagePipeline: @unchecked Sendable {
return task.process(.finished(.failure(.pipelineInvalidated)))
}
// TODO: Check this and other .cancelled callbacks
// The problem is that if cancelled is called before that
// `startImageTask` is called, then the tasks[task] is empty
// in `ImageTask` callback and cancelation logic fails to run
// This can happen if the task is cancelled from `imageTaskCreated`
guard task.state != .cancelled else {
return task.process(.cancelled)
}
Expand Down

0 comments on commit ec92d73

Please sign in to comment.