0Pricing
Swift Academy · บทเรียน

รายการจับค่าและ weak self

หลีกเลี่ยงวงจรการคงอยู่ด้วย [weak self]

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

ความเสี่ยงจากวงจรการเก็บอ้างอิง

เมื่อ object เก็บ closure แบบ escaping ที่จับ self ไว้อย่างเหนียวแน่น ทั้งสองจะทำให้อีกฝ่ายยังคงอยู่ตลอดไป — เกิดเป็น วงจรการเก็บอ้างอิง ที่ทำให้หน่วยความจำรั่ว

วงจรแบบ Strong

closure จับ self ไว้อย่างเหนียวแน่น และ self ก็เก็บ closure ไว้ — จึงไม่มีฝ่ายใดถูกคืนหน่วยความจำ:

class Owner {
    var onEvent: (() -> Void)?
    func setup() {
        onEvent = { print(self.describe()) }  // strong self -> cycle
    }
    func describe() -> String { "Owner" }
}
let o = Owner(); o.setup()
o.onEvent?()  // "Owner"  (but leaks)

รายการจับ

รายการจับ ที่อยู่ต้น closure เช่น { [weak self] in ... } จะควบคุมวิธีเก็บ reference ที่ถูกจับแต่ละรายการ โดยใช้ weak หรือ unowned แทน strong

ตัดวงจรด้วย weak self

[weak self] จะจับ self เป็นค่าทางเลือกที่ไม่ทำให้ self ยังคงอยู่:

class Owner {
    var onEvent: (() -> Void)?
    func setup() {
        onEvent = { [weak self] in
            print(self?.describe() ?? "gone")
        }
    }
    func describe() -> String { "Owner" }
}
let o = Owner(); o.setup()
o.onEvent?()  // "Owner"  (no cycle)

weak ทำให้ self เป็นค่าทางเลือก

เมื่อใช้ [weak self] self จะกลายเป็น Self? ดังนั้นคุณจึงต้องแกะค่าก่อนใช้งาน:

class Worker {
    var tag = "W"
    lazy var job: () -> Void = { [weak self] in
        guard let self = self else { return }
        print(self.tag)
    }
}
let w = Worker()
w.job()  // "W"

รูปแบบ guard let self

ผูกค่า self ใหม่ตั้งแต่ต้น เพื่อให้ส่วนที่เหลือของ closure ใช้ reference แบบ strong ที่ไม่ใช่ค่าทางเลือก:

class Service {
    var name = "S"
    lazy var run: () -> Void = { [weak self] in
        guard let self else { return }
        print(self.name)
        print("still \(self.name)")
    }
}
Service().run()  // "S" / "still S"

weak เทียบกับ unowned

weak ให้ค่าทางเลือกและปลอดภัยหาก object อาจหายไป ส่วน unowned ไม่ใช่ค่าทางเลือกและเร็วกว่า แต่จะทำให้โปรแกรม หยุดทำงาน หากเข้าถึงหลังจาก object ถูกคืนหน่วยความจำแล้ว — ใช้เฉพาะเมื่อรับประกันว่า self จะมีอายุยืนกว่า closure

การใช้ unowned

เลือกใช้ unowned เมื่อ closure ไม่สามารถมีอายุยืนกว่า self ได้:

class Timer2 {
    var ticks = 0
    lazy var tick: () -> Void = { [unowned self] in
        self.ticks += 1
    }
}
let t = Timer2()
t.tick(); t.tick()
print(t.ticks)  // 2

การจับเฉพาะ Property ที่ต้องใช้

จับเฉพาะสิ่งที่ต้องใช้แทนการจับ self ทั้งหมด — บางครั้งวิธีนี้ช่วยหลีกเลี่ยงวงจรได้โดยสิ้นเชิง:

class VM {
    let id = 42
    lazy var printer: () -> Void = { [id] in print(id) }
}
VM().printer()  // 42

Non-Escaping ไม่ต้องใช้ weak

closures แบบ synchronous และ non-escaping (เช่น map) ไม่ทำให้เกิดวงจร ดังนั้นการจับ self แบบ strong ในกรณีนี้จึงทำได้:

class Calc {
    let factor = 3
    func scale(_ xs: [Int]) -> [Int] {
        xs.map { $0 * self.factor }   // safe, non-escaping
    }
}
print(Calc().scale([1, 2]))  // [3, 6]

หลักทั่วไป

ใช้ [weak self] สำหรับ closures ที่เก็บไว้หรือเป็นแบบ escaping และอ้างถึง self เลือกใช้ unowned เฉพาะเมื่อรับประกันว่า self ยังมีอยู่ ข้ามรายการจับสำหรับ closures แบบ non-escaping

class P {
    var n = "P"
    var stored: (() -> Void)?
    func arm() { stored = { [weak self] in print(self?.n ?? "-") } }
}
let p = P(); p.arm(); p.stored?()  // "P"

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

เหตุใดจึงใช้ [weak self] ใน closure แบบ escaping ที่เก็บไว้

สรุป

คุณได้เรียนรู้เกี่ยวกับรายการจับ:

  • self แบบ strong ใน closure แบบ escaping ที่เก็บไว้จะสร้างวงจรการเก็บอ้างอิง (หน่วยความจำรั่ว)
  • [weak self] จะตัดวงจรนั้น โดย self จะกลายเป็นค่าทางเลือก ให้ใช้ guard let self
  • unowned ไม่ใช่ค่าทางเลือกและเร็วกว่า แต่จะทำให้โปรแกรมหยุดทำงานหาก self หายไป
  • closures แบบ non-escaping ไม่จำเป็นต้องใช้รายการจับ

ถัดไป: autoclosures

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

บทเรียน “รายการจับค่าและ weak self” ฟรีหรือไม่

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

คุณจะเรียนรู้อะไรในบทเรียน “รายการจับค่าและ weak self”

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

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

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

บทเรียน “รายการจับค่าและ weak self” ใช้เวลานานแค่ไหน

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

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

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

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

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