-
Meet async/await in Swift
Swift now supports asynchronous functions — a pattern commonly known as async/await. Discover how the new syntax can make your code easier to read and understand. Learn what happens when a function suspends, and find out how to adapt existing completion handlers to asynchronous functions.
Recursos
- SE-0310: Effectful read-only properties
- SE-0300: Continuations for interfacing async tasks with synchronous code
- SE-0297: Concurrency Interoperability with Objective-C
- SE-0296: Async/await
- The Swift Programming Language: Concurrency
Videos relacionados
WWDC22
- Efficiency awaits: Background tasks in SwiftUI
- Eliminate data races using Swift Concurrency
- Use Xcode for server-side development
- Visualize and optimize Swift concurrency
WWDC21
- Bring Core Data concurrency to Swift and SwiftUI
- Diagnose unreliable code with test repetitions
- Discover concurrency in SwiftUI
- Explore structured concurrency in Swift
- Friday@WWDC21
- Meet AsyncSequence
- Monday@WWDC21
- Protect mutable state with Swift actors
- Swift concurrency: Behind the scenes
- Swift concurrency: Update a sample app
- Use async/await with URLSession
- What's new in AppKit
- What's new in CloudKit
- What‘s new in Swift
- What’s new in AVFoundation
-
Buscar este video…
-
-
3:43 - Writing a function using completion handlers
func fetchThumbnail(for id: String, completion: @escaping (UIImage?, Error?) -> Void) { let request = thumbnailURLRequest(for: id) let task = URLSession.shared.dataTask(with: request) { data, response, error in if let error = error { completion(nil, error) } else if (response as? HTTPURLResponse)?.statusCode != 200 { completion(nil, FetchError.badID) } else { guard let image = UIImage(data: data!) else { completion(nil, FetchError.badImage) return } image.prepareThumbnail(of: CGSize(width: 40, height: 40)) { thumbnail in guard let thumbnail = thumbnail else { completion(nil, FetchError.badImage) return } completion(thumbnail, nil) } } } task.resume() } -
8:00 - Using completion handlers with the Result type
func fetchThumbnail(for id: String, completion: @escaping (Result<UIImage, Error>) -> Void) { let request = thumbnailURLRequest(for: id) let task = URLSession.shared.dataTask(with: request) { data, response, error in if let error = error { completion(.failure(error)) } else if (response as? HTTPURLResponse)?.statusCode != 200 { completion(.failure(FetchError.badID)) } else { guard let image = UIImage(data: data!) else { completion(.failure(FetchError.badImage)) return } image.prepareThumbnail(of: CGSize(width: 40, height: 40)) { thumbnail in guard let thumbnail = thumbnail else { completion(.failure(FetchError.badImage)) return } completion(.success(thumbnail)) } } } task.resume() } -
8:30 - Using async/await
func fetchThumbnail(for id: String) async throws -> UIImage { let request = thumbnailURLRequest(for: id) let (data, response) = try await URLSession.shared.data(for: request) guard (response as? HTTPURLResponse)?.statusCode == 200 else { throw FetchError.badID } let maybeImage = UIImage(data: data) guard let thumbnail = await maybeImage?.thumbnail else { throw FetchError.badImage } return thumbnail } -
13:15 - Async properties
extension UIImage { var thumbnail: UIImage? { get async { let size = CGSize(width: 40, height: 40) return await self.byPreparingThumbnail(ofSize: size) } } } -
14:17 - Async sequences
for await id in staticImageIDsURL.lines { let thumbnail = await fetchThumbnail(for: id) collage.add(thumbnail) } let result = await collage.draw() -
21:22 - Testing using XCTestExpectation
class MockViewModelSpec: XCTestCase { func testFetchThumbnails() throws { let expectation = XCTestExpectation(description: "mock thumbnails completion") self.mockViewModel.fetchThumbnail(for: mockID) { result, error in XCTAssertNil(error) expectation.fulfill() } wait(for: [expectation], timeout: 5.0) } } -
21:56 - Testing using async/await
class MockViewModelSpec: XCTestCase { func testFetchThumbnails() async throws { XCTAssertNoThrow(try await self.mockViewModel.fetchThumbnail(for: mockID)) } } -
22:30 - Bridging from sync to async
struct ThumbnailView: View { @ObservedObject var viewModel: ViewModel var post: Post @State private var image: UIImage? var body: some View { Image(uiImage: self.image ?? placeholder) .onAppear { Task { self.image = try? await self.viewModel.fetchThumbnail(for: post.id) } } } } -
25:56 - Async APIs in the SDK
import ClockKit extension ComplicationController: CLKComplicationDataSource { func currentTimelineEntry(for complication: CLKComplication) async -> CLKComplicationTimelineEntry? { let date = Date() let thumbnail = try? await self.viewModel.fetchThumbnail(for: post.id) guard let thumbnail = thumbnail else { return nil } let entry = self.createTimelineEntry(for: thumbnail, date: date) return entry } } -
26:59 - Async alternatives and continuations
// Existing function func getPersistentPosts(completion: @escaping ([Post], Error?) -> Void) { do { let req = Post.fetchRequest() req.sortDescriptors = [NSSortDescriptor(key: "date", ascending: true)] let asyncRequest = NSAsynchronousFetchRequest<Post>(fetchRequest: req) { result in completion(result.finalResult ?? [], nil) } try self.managedObjectContext.execute(asyncRequest) } catch { completion([], error) } } // Async alternative func persistentPosts() async throws -> [Post] { typealias PostContinuation = CheckedContinuation<[Post], Error> return try await withCheckedThrowingContinuation { (continuation: PostContinuation) in self.getPersistentPosts { posts, error in if let error = error { continuation.resume(throwing: error) } else { continuation.resume(returning: posts) } } } } -
31:44 - Storing the continuation for delegate callbacks
class ViewController: UIViewController { private var activeContinuation: CheckedContinuation<[Post], Error>? func sharedPostsFromPeer() async throws -> [Post] { try await withCheckedThrowingContinuation { continuation in self.activeContinuation = continuation self.peerManager.syncSharedPosts() } } } extension ViewController: PeerSyncDelegate { func peerManager(_ manager: PeerManager, received posts: [Post]) { self.activeContinuation?.resume(returning: posts) self.activeContinuation = nil // guard against multiple calls to resume } func peerManager(_ manager: PeerManager, hadError error: Error) { self.activeContinuation?.resume(throwing: error) self.activeContinuation = nil // guard against multiple calls to resume } }
-