Swift Academy · บทเรียน

การเชื่อมโค้ดเรียกกลับเดิม/Combine เข้ากับ async/await

ห่อ completion handlers ด้วย withCheckedContinuation / withCheckedThrowingContinuation และเชื่อม publisher ของ Combine เข้ากับ AsyncSequence เพื่อใช้ลูป for await อย่างง่าย

บทเรียน 2 จาก 38 ขั้นตอน

การเชื่อมโค้ดเรียกกลับเดิม/Combine เข้ากับ async/await เป็นบทเรียน Swift Academy ฟรีบน CoddyKit นี่คือบทเรียนที่ 2 จากทั้งหมด 3 บทเรียน คุณสามารถอ่านบทเรียนทั้งหมดด้านล่างฟรี — จากนั้นลองปฏิบัติด้วยตัวคุณเองในเบราว์เซอร์พร้อมตัวแก้ไขโค้ดในตัวและติวเตอร์ AI ตลอด 24/7 บทเรียนนี้เป็นส่วนหนึ่งของเส้นทางการเรียน Swift Academy และความก้าวหน้าของคุณจะซิงค์ข้ามเว็บและแอป CoddyKit คอร์ส Swift Academy มีบทเรียนทั้งหมด 3 บทเรียน

เหตุใดจึงต้องเชื่อมต่อ

เป้าหมาย: ใช้ความต่อเนื่องเพื่อห่อหุ้มการเรียกกลับ และจัดการสตรีมของ คอมไบน์ ในรูปแบบ AsyncSequence

  • ความต่อเนื่อง (แบบไม่โยนข้อผิดพลาด / แบบโยนข้อผิดพลาด)
  • ตัวอย่างการเชื่อมต่อยูอาร์แอลเซสชัน
  • การใช้ for await กับคอมไบน์

ความต่อเนื่องแบบไม่โยนข้อผิดพลาด

ใช้ withCheckedContinuation เมื่อ API เดิมไม่สามารถล้มเหลวได้ ดำเนินการต่อให้ตรงหนึ่งครั้ง

// Old-style API
func fetchName(completion: @escaping (String) -> Void) {
    // simulate async
    Task { try? await Task.sleep(nanoseconds: 80_000_000); completion("Ana") }
}

// Async wrapper using continuation (non-throwing)
func fetchName() async -> String {
    await withCheckedContinuation { (cont: CheckedContinuation<String, Never>) in
        fetchName { value in cont.resume(returning: value) }
    }
}

Task {
    let name = await fetchName()
    print("name:", name) // "Ana"
}

ความต่อเนื่องแบบโยนข้อผิดพลาด

ใช้ withCheckedThrowingContinuation เพื่อส่งต่อข้อผิดพลาดจาก API เดิมผ่าน throw ตรวจสอบให้มีเส้นทาง resume เพียงเส้นทางเดียว

enum NetError: Error { case offline; case badStatus }

func loadNumber(completion: @escaping (Result<Int, Error>) -> Void) {
    Task {
        try? await Task.sleep(nanoseconds: 80_000_000)
        completion(.failure(NetError.offline))
    }
}

func loadNumber() async throws -> Int {
    try await withCheckedThrowingContinuation { (cont: CheckedContinuation<Int, Error>) in
        loadNumber { result in
            switch result {
            case .success(let v): cont.resume(returning: v)
            case .failure(let e): cont.resume(throwing: e)
            }
        }
    }
}

Task {
    do {
        let n = try await loadNumber()
        print(n)
    } catch {
        print("error:", error) // offline
    }
}

การเชื่อมต่อ URLSession

ห่อหุ้ม API ที่ใช้ตัวจัดการการเสร็จสิ้น (เช่น URLSession) เพื่อให้ได้ฟังก์ชันแบบอะซิงโครนัสที่โยนข้อผิดพลาดได้อย่างสะอาด อย่าลืม resume เพียงครั้งเดียว

import Foundation

func getText(from url: URL) async throws -> String {
    try await withCheckedThrowingContinuation { (cont: CheckedContinuation<String, Error>) in
        let task = URLSession.shared.dataTask(with: url) { data, resp, err in
            if let err = err { cont.resume(throwing: err); return }
            guard let data = data, let text = String(data: data, encoding: .utf8) else {
                cont.resume(throwing: URLError(.badServerResponse)); return
            }
            cont.resume(returning: text)
        }
        task.resume()
    }
}

// Demo (works in environments with network access)
let demoURL = URL(string: "https://example.com")!
Task {
    do { let body = try await getText(from: demoURL); print(body.prefix(15)) }
    catch { print("network error:", error) }
}

คอมไบน์ในรูปแบบ AsyncSequence

ผู้เผยแพร่ของคอมไบน์จำนวนมากเปิดเผย .values ทำให้คุณสามารถวน&ให้อ่านค่าที่ส่งออกได้โดยไม่ต้องสร้างตัวเชื่อมต่อเอง

import Combine
import Foundation

let subject = PassthroughSubject<Int, Never>()

// Consume Combine as AsyncSequence:
Task {
    var produced: [Int] = []
    for await value in subject.values {          // Publisher.values -> AsyncSequence
        produced.append(value)
        if produced.count == 3 { break }         // stop after 3 values
    }
    print("collected:", produced)                // e.g., [1,2,3]
}

// Publish a few values
var cancellables = Set<AnyCancellable>()
Timer.publish(every: 0.05, on: .main, in: .common)
    .autoconnect()
    .prefix(3)
    .scan(0) { acc, _ in acc + 1 }
    .sink { subject.send($0) }
    .store(in: &cancellables)

ผู้เผยแพร่ → AsyncStream

หากไม่มี .values ให้สร้างตัวเชื่อมต่อขนาดเล็กด้วย AsyncStream อย่าลืมใช้ cancel กับการสมัครรับเมื่อทำงานเสร็จ

import Combine

// Bridge ANY Publisher to AsyncSequence using AsyncStream (simple version)
extension Publisher {
    func asAsyncStream() -> AsyncStream<Output> {
        AsyncStream { continuation in
            let cancel = self.sink(
                receiveCompletion: { _ in continuation.finish() },
                receiveValue: { value in continuation.yield(value) }
            )
            continuation.onTermination = { _ in cancel.cancel() }
        }
    }
}

// Demo:
let pub = [10, 20, 30].publisher
Task {
    var sum = 0
    for await v in pub.asAsyncStream() { sum += v }
    print("sum:", sum) // 60
}

ใช้ความต่อเนื่องแบบโยนข้อผิดพลาด

ตรวจสอบสั้น ๆ: วิธีที่ดีที่สุดในการเชื่อมการเรียกกลับที่ล้มเหลวเข้ากับการทำงานแบบอะซิงโครนัสคืออะไร

สรุปทบทวน

สรุปทบทวน: ห่อหุ้มการเรียกกลับจาก API เดิมด้วยความต่อเนื่อง (แบบโยนข้อผิดพลาดหรือไม่โยน) และรับข้อมูลจากคอมไบน์ โดยใช้ .values หรือตัวเชื่อมต่อขนาดเล็กของ AsyncStream ให้การดำเนินการต่อเกิดเพียงครั้งเดียว และยกเลิกการสมัครรับเมื่อเสร็จสิ้น

เริ่มต้นได้ฟรี

เรียนรู้ Swift ด้วย AI tutor — ฟรี

เขียนและเรียกใช้โค้ดจริงในเบราว์เซอร์ของคุณ รับความช่วยเหลือทันทีจาก AI tutor 24/7 และเรียนรู้ต่อจากที่คุณหยุดบนเว็บหรือในแอป

คอร์ส
122
บทเรียน
409

คำถามที่พบบ่อย

บทเรียน “การเชื่อมโค้ดเรียกกลับเดิม/Combine เข้ากับ async/await” ฟรีหรือไม่

ใช่ — ข้อความเต็มของ “การเชื่อมโค้ดเรียกกลับเดิม/Combine เข้ากับ async/await” ฟรีให้อ่านที่นี่บนเว็บ เพื่อปฏิบัติแบบโต้ตอบ (ตัวแก้ไขโค้ดในตัวและติวเตอร์ AI ตลอด 24/7) และปลดล็อคส่วนที่เหลือของคอร์ส Swift Academy ให้อัปเกรดเป็น CoddyKit PRO คอร์ส Swift Academy มีบทเรียนทั้งหมด 3 บทเรียน

คุณจะเรียนรู้อะไรในบทเรียน “การเชื่อมโค้ดเรียกกลับเดิม/Combine เข้ากับ async/await”

ห่อ completion handlers ด้วย withCheckedContinuation / withCheckedThrowingContinuation และเชื่อม publisher ของ Combine เข้ากับ AsyncSequence เพื่อใช้ลูป for await อย่างง่าย คุณปฏิบัติ Swift Academy ด้วยโค้ดที่ใช้งานได้จริงที่คุณเรียกใช้โดยตรงในเบราว์เซอร์ และติวเตอร์ AI ตลอด 24/7 ตอบคำถามของคุณขณะที่คุณไปผ่านบทเรียน

คุณต้องมีประสบการณ์ก่อนที่จะเริ่มเรียน Swift Academy หรือไม่

ไม่จำเป็นต้องมีประสบการณ์มาก่อน Swift Academy บน CoddyKit ออกแบบมาสำหรับผู้เริ่มต้นไปจนถึงผู้เรียนขั้นสูง คุณสามารถเริ่มต้นที่นี่หรือเริ่มจากตัวแรกและเรียนด้วยความเร็วของคุณเอง นี่คือบทเรียนที่ 2 จากทั้งหมด 3 บทเรียน

บทเรียน “การเชื่อมโค้ดเรียกกลับเดิม/Combine เข้ากับ async/await” ใช้เวลานานแค่ไหน

บทเรียน CoddyKit ส่วนใหญ่ใช้เวลาประมาณ 5–10 นาที แต่ละบทเรียนจึงสั้นและเป็นแบบโต้ตอบ คุณสามารถก้าวหน้าอย่างต่อเนื่องและกลับมาเรียนต่อจากตรงที่เพิ่งหยุดบนเว็บและแอปได้เลย

ฉันเขียนและรันโค้ดในบทเรียน Swift Academy นี้ได้ไหม

ได้ บทเรียน Swift Academy ทุกบทมีตัวแก้ไขโค้ดในตัว คุณจึงเขียนและรันโค้ดจริงได้เลยในเบราว์เซอร์ และได้รับข้อเสนอแนะจาก AI ในทันที — ไม่ต้องติดตั้งในเครื่องของคุณ

บทเรียนทั้งหมดในหลักสูตรนี้

  1. ผู้ผลิต/ผู้บริโภค สายงาน และการหมดเวลา
  2. การเชื่อมโค้ดเรียกกลับเดิม/Combine เข้ากับ async/await
  3. การทดสอบโค้ด async (XCTest)
← กลับไปที่ Swift Academy