← Back to list

Swift Concurrency — Image Load

WWDC25: Embracing Swift concurrency | Apple

Hailey · 2025-09-29 05:33 · 1 claps · 2.7 min read paywalled
#swift-concurrency #wwdc25 #ios-app-development #swiftui #swift
Open on Medium ↗
Wiki topics: 📱 · Mobile Development

Swift | iOS

Swift Concurrency — Image Load

Summary - WWDC25: Embracing Swift concurrency | Apple

There are no new pictures of me this season🏖️, I’ve just been studying from last winter. I hope it pays off in the end.

Breaking ties to the main actor

  • Move main actor code to @MainActor functions
  • Use await to access the main actor asynchronously
  • Add nonisolated to code that does not need the main actor

Key point for this session.

  • @concurrent : always runs in the background (not always the best, small)
  • nonisolated : (no thread change) follows previous thread -> WWDC23 Beyond the basic of structured concurrency

URL : value type

that means, when we copy that into the background thread, it copys independently. so, even the (background) url gets changed, original Url has no effect with the new value.

url(value type) safe to share, because it duplicates.

url(value type) safe to share, because it duplicates.

  • Sendable(protocol): always safe to share concurrently = inherited for value type = copied independently, return a new value
  • Actors (main actor …) protect non-Sendable state = not shared at the same time. only ever accessed by one task at a time. return a reference.

for non-sendable classes

in @concurrent, you need to use await for mainthread tasks (all are available). there are 3 ways you can do:

//reference type
nonisolated class MyImage {
  var width: Int
  var height: Int
  var pixels: [Color]
  var url: URL
}

//------- A
@concurrent
func scaleAndDisplay(urlString: String) async {
  let image = loadImage(urlString)
  image.scaleImage(by: 0.5)
  await view.displayImage(image) ✅ mainthread saperately
}

//------- B
// It makes sure the task order.
func scaleAndDisplay(urlString: String) async {
  Task { @concurrent
    let image = loadImage(urlString)
    image.scaleImage(by: 0.5)
    await view.displayImage(image) ✅mainthread saperately
  }
}

//------- C
// A capture of the image variable. 
// closure with shared state is still safe
// as long as it isn't called concurrently
func scaleAndDisplay(urlString: String) async {
  let image = loadImage(urlString)
  await perform(afterDelay(0.1) {
    image.scaleImage(by: 0.5) ✅ change saperately in the background thread
  }
  view.displayImage(image) ✅ mainthread 
}

func perform(afterDelay delay: Double, body: () -> Void) async throws -> Image {
  if #available(iOS 16.0, *) {
      try await Task.sleep(for: .seconds(delay))
   } else {
      // Fallback on earlier versions
   }
   body()

  }

Actors

  • coordinate access to data across many tasks

But most classes are not actors

  • UI-facing classes : @MainActor
  • Model classes: @MainActor or non-Sendable

Conclusion

  • Share Sendable types in concurrent code
  • Use mutable classes and closures in one task at a time
  • Change mutable state before sending to another task

Blazing Keyboard Time!

Blazing Keyboard Time!

If you use Actor with codable(decodable) you will face this error:

  1. Check build setting

Target -> Building Settings -> Default Actor Isolation

Target -> Building Settings -> Default Actor Isolation

If you use MainActor for default, Xcode will implicitly isolate these types to @MainActor

Class, Struct, Enum

Fixed: use nonisolated

nonisolated struct APIResponse<T: Codable & Sendable>: Codable {
    let info: Info?
    let results: T // actual data
}

Your one clap 👏 makes me encouraged 🔥 Thank you🙇‍♀️


메타데이터
post_id
2418c2c91c56
slug
swift-concurrency-image-load-2418c2c91c56
url
https://medium.com/@hailey.plist/swift-concurrency-image-load-2418c2c91c56
canonical_url
https://medium.com/@hailey.plist/swift-concurrency-image-load-2418c2c91c56
author_url
https://medium.com/@hailey.plist
status
ok
fetched_at
2026-07-17 04:53:12