Swift Academy · บทเรียน

คลอเชอร์ที่หลุดออกนอกขอบเขต

จัดเก็บคลอเชอร์ที่มีอายุยืนกว่าฟังก์ชันของตน

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

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

Escaping เทียบกับ Non-Escaping

โดยค่าเริ่มต้น พารามิเตอร์ closure จะเป็นแบบ non-escaping ซึ่งหมายความว่าต้องเรียกใช้ก่อนฟังก์ชันคืนค่า ให้ระบุ @escaping หาก closure อาจถูกเก็บไว้และเรียกใช้ภายหลัง

Closure แบบ Non-Escaping

closure นี้ทำงานแบบพร้อมกันและจะหายไปเมื่อฟังก์ชันคืนค่า:

func run(_ work: () -> Void) {
    work()
}
run { print("done now") }  // "done now"

เหตุใดจึงต้องใช้ @escaping

การเก็บ closure ไว้ใช้ภายหลังจำเป็นต้องใช้ @escaping:

var handlers: [() -> Void] = []
func register(_ handler: @escaping () -> Void) {
    handlers.append(handler)  // escapes the function
}
register { print("later") }
handlers[0]()  // "later"

Escaping กับงานแบบไม่พร้อมกัน

completion handlers จะหลุดออกนอกขอบเขต เพราะทำงานหลังจากฟังก์ชันคืนค่าแล้ว:

func load(then completion: @escaping (String) -> Void) {
    // imagine async work
    completion("data")
}
load { result in print(result) }  // "data"

ต้องระบุ self อย่างชัดเจน

ภายใน closure แบบ escaping คุณต้องเขียน self. อย่างชัดเจนเมื่อเข้าถึงสมาชิกของ instance — เพื่อเตือนว่า closure อาจเก็บ self ไว้

การระบุ self อย่างชัดเจนใน Escaping

คอมไพเลอร์กำหนดให้ต้องมีการอ้างอิงอย่างชัดเจน:

class Loader {
    var name = "L"
    func start(_ done: @escaping () -> Void) {
        let cb = { print(self.name); done() }
        cb()
    }
}
Loader().start { print("finished") }  // "L" then "finished"

การเก็บ Callback หลายรายการ

closures แบบ escaping ช่วยให้คุณสร้างรายการผู้สังเกตการณ์ได้:

class Emitter {
    private var listeners: [(Int) -> Void] = []
    func on(_ l: @escaping (Int) -> Void) { listeners.append(l) }
    func fire(_ v: Int) { listeners.forEach { $0(v) } }
}
let e = Emitter()
e.on { print("got \($0)") }
e.fire(7)  // "got 7"

การคืนค่า Closure ที่เก็บไว้

closures ที่เก็บไว้ใน property จะเป็นแบบ escaping:

class Button {
    var action: (() -> Void)?
    func setAction(_ a: @escaping () -> Void) { action = a }
}
let b = Button()
b.setAction { print("tapped") }
b.action?()  // "tapped"

Closure ทางเลือกเป็น Escaping

พารามิเตอร์ closure แบบทางเลือกจะเป็น escaping โดยปริยาย (เพราะถูกห่ออยู่ใน Optional) จึงสามารถจัดเก็บไว้ได้:

func maybe(_ f: (() -> Void)?) {
    f?()
}
maybe { print("ran") }  // "ran"

การส่ง Escaping เข้าอาร์เรย์ของงาน

คิวของงานที่เลื่อนเวลาไว้เป็นกรณีใช้งานแบบ escaping ที่พบได้ทั่วไป — closure แต่ละตัวจะถูกเก็บไว้ แล้วจึงเรียกใช้ภายหลัง:

var tasks: [() -> Int] = []
func schedule(_ task: @escaping () -> Int) {
    tasks.append(task)
}
schedule { 1 + 1 }
schedule { 10 * 2 }
print(tasks.map { $0() })  // [2, 20]

หมายเหตุด้านประสิทธิภาพ

closures แบบ non-escaping สามารถปรับประสิทธิภาพได้มากกว่า (ไม่จำเป็นต้องจัดสรรหน่วยความจำบน heap) ให้ closures เป็นแบบ non-escaping เมื่อทำได้ และใช้ escaping เฉพาะเมื่อคุณเก็บหรือเลื่อนเวลาไว้จริง ๆ

func sum(_ xs: [Int], _ f: (Int) -> Int) -> Int {
    xs.reduce(0) { $0 + f($1) }   // non-escaping, fast
}
print(sum([1, 2, 3]) { $0 * $0 })  // 14

ตรวจสอบอย่างรวดเร็ว

เมื่อใดจึงต้องระบุพารามิเตอร์ closure ด้วย @escaping

สรุป

คุณได้เรียนรู้เกี่ยวกับ closures แบบ escaping:

  • แบบ non-escaping เป็นค่าเริ่มต้น โดย closures จะทำงานก่อนฟังก์ชันคืนค่า
  • ต้องใช้ @escaping เพื่อจัดเก็บหรือเลื่อนเวลา closure
  • closures แบบ escaping ต้องเข้าถึง self. อย่างชัดเจน
  • พารามิเตอร์ closure แบบทางเลือกจะเป็น escaping โดยปริยาย ควรเลือกแบบ non-escaping เพื่อความเร็ว

ถัดไป: รายการจับและ weak self

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

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

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

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

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

บทเรียน “คลอเชอร์ที่หลุดออกนอกขอบเขต” ฟรีหรือไม่

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

คุณจะเรียนรู้อะไรในบทเรียน “คลอเชอร์ที่หลุดออกนอกขอบเขต”

จัดเก็บคลอเชอร์ที่มีอายุยืนกว่าฟังก์ชันของตน คุณปฏิบัติ Swift Academy ด้วยโค้ดที่ใช้งานได้จริงที่คุณเรียกใช้โดยตรงในเบราว์เซอร์ และติวเตอร์ AI ตลอด 24/7 ตอบคำถามของคุณขณะที่คุณไปผ่านบทเรียน

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

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

บทเรียน “คลอเชอร์ที่หลุดออกนอกขอบเขต” ใช้เวลานานแค่ไหน

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

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

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

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

  1. การจับค่าด้วยการอ้างอิง
  2. คลอเชอร์ที่หลุดออกนอกขอบเขต
  3. รายการจับค่าและ weak self
  4. Autoclosures
← กลับไปที่ Swift Academy