Unowned Reference: คืออะไร ไวยากรณ์และการใช้งานในแอปพลิเคชันมือถือ

ผู้แต่ง: IT Sectr เผยแพร่เมื่อ: 2026-03-30 เวลาอ่าน: 9 นาที

Unowned Reference (การอ้างอิงแบบไม่มีเจ้าของ) คือการอ้างอิงแบบไม่เป็นเจ้าของใน Swift ที่ไม่เพิ่ม retain count ของออบเจ็กต์และไม่เหมือนกับ weak ตรงที่ไม่ถูกตั้งค่าเป็น nil หลังจากออบเจ็กต์ถูกปลดปล่อย ตาม Apple Swift Language Guide, 2026 จะใช้ unowned เมื่อรับประกันว่าออบเจ็กต์มีอายุอย่างน้อยเท่ากับออบเจ็กต์ที่อ้างอิงถึงมัน ไม่เหมือนกับ Weak Reference ตรงที่ unowned ไม่จำเป็นต้อง unwrap — มันเป็นชนิดที่ไม่จำเป็นต้องเลือก (non-optional) ซึ่งทำให้โค้ดสะอาดขึ้น แต่ส่งต่อความรับผิดชอบในการรับประกันอายุให้กับนักพัฒนา

ประเด็นสำคัญ

  • Unowned Reference — การอ้างอิงแบบไม่เป็นเจ้าของโดยไม่มีการทำให้เป็นศูนย์อัตโนมัติ ไม่จำเป็นต้องเลือก ไม่เพิ่ม retain count
  • การรับประกัน — ใช้เมื่อออบเจ็กต์ได้รับการรับประกันว่าไม่สามารถถูกปลดปล่อยก่อนออบเจ็กต์ที่อ้างอิงถึงมัน
  • ความแตกต่างจาก weak — unowned ไม่ถูกทำให้เป็น nil (เสี่ยงต่อการหยุดทำงาน) weak ถูกทำให้เป็น nil (ปลอดภัย)
  • สถานการณ์ — พ่อแม่-ลูกที่มีการรับประกันอายุ, closures กับ unowned self, ซิงเกิลตันและ Service Locator
  • ความเสี่ยง — การเข้าถึงออบเจ็กต์ unowned ที่ถูกปลดปล่อยทำให้เกิดการหยุดทำงานขณะ运行时 (EXC_BAD_ACCESS)

Unowned Reference คืออะไร?

Unowned Reference คือการอ้างอิงแบบไม่เป็นเจ้าของไปยังออบเจ็กต์ใน ARC ที่ไม่เพิ่ม retain count ของมัน ไม่เหมือนกับ weak ตรงที่การอ้างอิง unowned จะไม่ถูกทำให้เป็นศูนย์หลังจากการจัดสรรหน่วยความจำของออบเจ็กต์: มันยังคงชี้ไปยังหน่วยความจำที่ถูกปลดปล่อยแล้ว การเข้าถึงการอ้างอิงดังกล่าวทำให้เกิดการหยุดทำงานขณะ运行时ด้วย EXC_BAD_ACCESS

คำว่า “ไม่มีเจ้าของ” สะท้อนถึงความหมาย: ออบเจ็กต์มีอยู่ แต่ไม่มีใครรับผิดชอบอายุของมัน นักพัฒนาประกาศอย่างชัดเจน: “ฉันรับประกันว่าออบเจ็กต์นี้จะมีชีวิตอยู่ตราบเท่าที่ฉันอ้างอิงถึงมัน” คอมไพเลอร์ไม่ตรวจสอบการรับประกันนี้ — มันเป็นสัญญาในระดับนักพัฒนา

ตาม Swift.org Documentation, 2026 การอ้างอิง unowned เป็นที่นิยมมากกว่า weak ในสถานการณ์ที่มีการรับประกันอายุเพราะ: ไม่ต้องการชนิดที่เลือกได้ (โค้ดสะอาดกว่า), ไม่ต้องการ unwrap (ลด force-unwrap หรือ guard let), และไม่มีค่าใช้จ่ายในการบำรุงรักษาตาราง weak สำหรับการทำให้เป็นศูนย์ อย่างไรก็ตาม การละเมิดสัญญาใด ๆ จะส่งผลให้เกิดการหยุดทำงาน

ไวยากรณ์ unowned ใน Swift

ใน Swift การอ้างอิง unowned ถูกประกาศด้วยคำหลัก unowned ก่อน let หรือ var ไม่เหมือนกับ weak ตรงที่ unowned สามารถเป็น ทั้ง let และ var และไม่ต้องการชนิดที่เลือกได้ คุณสมบัตินี้ทำให้ unowned สะดวกสำหรับการอ้างอิงที่ไม่สามารถเป็น nil ตามตรรกะของโดเมน

swift
class Country {
    let name: String
    var capital: City!           // จะถูกตั้งค่าหลังจากการเริ่มต้น
    init(name: String) { self.name = name }
}

class City {
    let name: String
    unowned let country: Country   // ✅ unowned let — การรับประกันอายุ

    init(name: String, country: Country) {
        self.name = name
        self.country = country
    }
}

// การใช้งาน
let france = Country(name: "France")
let paris = City(name: "Paris", country: france)
france.capital = paris
// ✅ Country → City (strong), City → Country (unowned) — ไม่มี retain cycle

ในตัวอย่างนี้ City unowned let country — เมืองไม่สามารถดำรงอยู่ได้โดยไม่มีประเทศ หากประเทศหายไป เมือง (และการอ้างอิง) จะสูญเสียความหมาย ทางความหมายแล้ว นี่เป็นกรณีที่เหมาะสำหรับ unowned: การรับประกันอายุมีอยู่ ไม่จำเป็นต้องเลือก ไม่เกิด retain cycle

unowned var

unowned var อนุญาตให้ใช้ได้แต่พบได้น้อยกว่า ใช้เมื่อการอ้างอิงอาจถูกแทนที่ (เช่น การเชื่อมลูกเข้ากับพ่อแม่คนอื่น) เมื่อกำหนดค่าใหม่ การจัดสรรหน่วยความจำของออบเจ็กต์เก่าเป็นความรับผิดชอบของเจ้าของภายนอก

Unowned Optional

ใน Swift 5.0+ ได้มีการนำการสนับสนุน unowned แบบเลือกได้ (unowned let x: Type?) มาใช้ นี่คือการประนีประนอม: unowned รับประกันว่าหากการอ้างอิงไม่ใช่ nil ออบเจ็กต์จะยังมีชีวิตอยู่ พฤติกรรมเมื่อถูกจัดสรรหน่วยความจำคือการหยุดทำงาน เช่นเดียวกับ unowned ทั่วไป

Unowned vs Weak: ควรใช้อะไรเมื่อใด

การเลือกระหว่าง unowned และ weak เป็นหนึ่งในการตัดสินใจที่พบบ่อยเมื่อออกแบบสถาปัตยกรรม Swift มาดูเกณฑ์และคำแนะนำสำหรับแต่ละกรณีกัน

เกณฑ์WeakUnowned
เลือกได้ใช่ (Type?)ไม่ (Type)
ทำให้เป็นศูนย์เมื่อจัดสรรอัตโนมัติเป็น nilไม่ (เสี่ยงพอยน์เตอร์ลอย)
ชนิด (let/var)var เท่านั้นlet หรือ var
ประสิทธิภาพค่าใช้จ่ายตาราง weakน้อยที่สุด (พอยน์เตอร์ธรรมดา)
ความปลอดภัยปลอดภัย (ตรวจสอบ nil)เสี่ยง EXC_BAD_ACCESS
การรับประกันอายุไม่จำเป็นต้องการการรับประกันที่ชัดเจน

กฎปฏิบัติ

ใช้ weak หากมีข้อสงสัยแม้เพียงเล็กน้อยเกี่ยวกับอายุของออบเจ็กต์ Weak ปลอดภัย ชัดเจน และไม่ต้องการหลักฐาน ใช้ unowned เฉพาะเมื่อคุณสามารถกำจัดสถานการณ์ทั้งหมดที่ออบเจ็กต์อาจถูกจัดสรรก่อนได้ กรณีทั่วไป: ลูกที่ไม่มีพ่อแม่ดำรงอยู่ไม่ได้; closure ที่ทำงานแบบซิงโครนัส; การเข้าถึงออบเจ็กต์ภายใน initializer ของมัน

ตาม Airbnb Swift Style Guide, 2025 ในฐานโค้ดขนาดใหญ่ แนะนำให้ใช้ weak เป็นค่าเริ่มต้น และใช้ unowned เฉพาะกับความคิดเห็นที่ชัดเจนซึ่งอธิบายการรับประกันอายุ ซึ่งช่วยลดความเสี่ยงของการหยุดทำงานที่ไม่ชัดเจนระหว่างการปรับโครงสร้าง

Unowned self ใน Closures

Closures เป็นกรณีการใช้งานที่พบบ่อยเป็นอันดับสองสำหรับ unowned รองจากความสัมพันธ์พ่อแม่-ลูก รายการจับ [unowned self] ใช้เมื่อรับประกันว่า self มีอายุยืนกว่า closure มาดูสถานการณ์ที่ถูกต้องและไม่ถูกต้องกัน

เมื่อ unowned self ปลอดภัย

Closure แบบซิงโครนัส — sorted, filter, map พวกมันทำงานทันทีในเธรดปัจจุบัน self ยังมีชีวิตอยู่อย่างแน่นอน รายการจับกับ unowned เป็นที่ยอมรับได้ที่นี่และให้โค้ดที่สะอาดกว่า

swift
class DataProcessor {
    var items: [Int] = [3, 1, 4, 1, 5]

    func processSorted() {
        // ✅ unowned self — sorted ทำงานแบบซิงโครนัส self รับประกันว่ายังมีชีวิต
        let sorted = items.sorted { [unowned self] a, b in
            return self.customCompare(a, b)
        }
    }

    func customCompare(_ a: Int, _ b: Int) -> Bool { return a < b }
}

เมื่อ unowned self อันตราย

Closure แบบอะซิงโครนัส — ที่มีความล่าช้า คำขอเครือข่าย แอนิเมชัน Self อาจถูกจัดสรรหน่วยความจำระหว่างการจัดกำหนดการ closure และการทำงานของมัน ที่นี่ unowned self นำไปสู่การหยุดทำงาน ใช้ [weak self]

swift
class NetworkLoader {
    func loadData() {
        // ❌ อันตราย: unowned self ใน closure แบบอะซิงโครนัส
        URLSession.shared.dataTask(with: url) { [unowned self] data, _, _ in
            self.handleResponse(data)  // หยุดทำงานหาก self ถูกปลดปล่อย
        }.resume()
    }

    func handleResponse(_ data: Data?) { }

    // ✅ ถูกต้อง: weak self + guard
    func loadDataSafe() {
        URLSession.shared.dataTask(with: url) { [weak self] data, _, _ in
            guard let self else { return }
            self.handleResponse(data)
        }.resume()
    }
}

จำกฎไว้: unowned self — เฉพาะสำหรับ closure แบบซิงโครนัสที่ทำงานทันที สำหรับ closure แบบอะซิงโครนัส ให้ใช้ weak self + guard let เสมอ ข้อยกเว้น: หากคุณเก็บการอ้างอิงไปยังออบเจ็กต์อย่างชัดเจนจนกว่า closure จะเสร็จสมบูรณ์ (เช่น การเก็บการอ้างอิงที่แข็งแกร่งในตัวแปรอื่น)

ความเสี่ยงของ unowned และวิธีหลีกเลี่ยง

Unowned เป็นเครื่องมือที่ทรงพลังแต่อันตราย มาดูสถานการณ์จริงที่ unowned อาจนำไปสู่การหยุดทำงานและวิธีการลดความเสี่ยงกัน

การปรับโครงสร้างและการเปลี่ยนแปลงการรับประกัน

ความเสี่ยงหลักของ unowned คือการเปลี่ยนแปลงในตรรกะทางธุรกิจที่ทำให้การรับประกันอายุเป็นโมฆะ นักพัฒนาปรับโครงสร้างโค้ด: เปลี่ยนความเป็นเจ้าของ, แนะนำการปลดปล่อยที่เลื่อนออกไป, เพิ่มการแคช — และการอ้างอิง unowned กลายเป็นระเบิดเวลา คอมไพเลอร์จะไม่เตือน — เฉพาะการหยุดทำงานบนอุปกรณ์ของผู้ใช้

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

Unowned ในลำดับชั้น UIKit

UIKit เป็นพื้นที่ที่มีความเสี่ยงสูงสำหรับ unowned ViewController สามารถถูกจัดสรรหน่วยความจำได้ตลอดเวลาในระหว่างการนำทาง (pop, dismiss), การโหลดหน่วยความจำออก หรือการเปลี่ยนทิศทาง หากคุณส่ง ViewController ไปยัง closure ด้วย unowned self self อาจเป็น nil เมื่อกลับจากพื้นหลังหรือเมื่อแอนิเมชันเสร็จสมบูรณ์

แนวปฏิบัติที่ดีที่สุด

เพื่อลดความเสี่ยงเมื่อใช้ unowned ให้ปฏิบัติตามกฎเหล่านี้:

  • เลือก weak เป็นค่าเริ่มต้น — weak ปลอดภัย unowned คือการเพิ่มประสิทธิภาพ ไม่ใช่มาตรฐาน
  • บันทึกการรับประกันเป็นเอกสาร — สำหรับแต่ละ unowned ให้เขียนความคิดเห็นพร้อมเหตุผล
  • หลีกเลี่ยง unowned ใน ViewController — วงจรชีวิตของ UIKit ไม่สามารถคาดเดาได้สำหรับการรับประกัน unowned
  • ใช้ unowned เฉพาะกับ closure แบบซิงโครนัส — sorted, filter, map เป็นตัวเลือกที่ปลอดภัย
  • ตรวจสอบระหว่างการตรวจสอบโค้ด — แต่ละ unowned ต้องมีเหตุผลจากผู้เขียนโค้ด
  • ย้ายไปใช้ weak เมื่อมีข้อสงสัยแม้เพียงเล็กน้อย — การสูญเสียความสามารถในการอ่าน (guard let หนึ่งครั้ง) ดีกว่าการหยุดทำงานในโปรดักชัน
swift
// ตัวอย่าง: การอ้างอิง unowned ที่ถูกบันทึกเป็นเอกสารพร้อมเหตุผลที่ชัดเจน
class InvoiceLineItem {
    let productName: String
    let price: Decimal

    // unowned Invoice — InvoiceLineItem ไม่สามารถดำรงอยู่ได้หากไม่มี Invoice
    // Invoice สร้าง Item และลบมันเมื่อถูกลบ
    // การรับประกัน: Invoice มีอายุอย่างน้อยเท่ากับ Item
    unowned let invoice: Invoice

    init(productName: String, price: Decimal, invoice: Invoice) {
        self.productName = productName
        self.price = price
        self.invoice = invoice
    }
}

// นี่คือการรับประกันที่แข็งแกร่ง: Invoice ลบ Item ทั้งหมดใน deinit
// การละเมิดการรับประกัน = บั๊กในตรรกะทางธุรกิจที่ต้องแก้ไข

การบันทึกการรับประกันเป็นเอกสารเป็นมาตรฐานทางวิชาชีพ ในโครงการขนาดใหญ่ (Airbnb, Uber) การตรวจสอบโค้ดต้องมีเหตุผลสำหรับแต่ละ unowned หากการรับประกันไม่ชัดเจน ให้ใช้ weak ความคิดเห็นบน unowned ช่วยให้นักพัฒนาในอนาคตเข้าใจว่าทำไมไม่ใช้ weak ที่นี่และเงื่อนไขใดที่อาจทำลายการรับประกัน

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

จะเกิดอะไรขึ้นเมื่อเข้าถึงการอ้างอิง unowned หลังจากออบเจ็กต์ถูกปลดปล่อย?

การหยุดทำงานขณะ运行时 ด้วย EXC_BAD_ACCESS Swift ไม่ตรวจสอบความถูกต้องของการอ้างอิง unowned เมื่อเข้าถึง — มันเป็นเพียงพอยน์เตอร์ “ดิบ” หากออบเจ็กต์ถูกปลดปล่อย หน่วยความจำจะถูกเขียนทับและการเข้าถึงมันจะสิ้นสุดอย่างร้ายแรง นี่เป็นข้อยกเว้นที่ไม่สามารถจับได้ (ไม่ใช่ try-catch)

สามารถใช้ unowned กับโปรโตคอลได้หรือไม่?

ได้ ถ้าโปรโตคอลสืบทอดจาก AnyObject Unowned ทำงานกับชนิดอ้างอิงทั้งหมด: คลาส, โปรโตคอล AnyObject, ออบเจ็กต์ Objective-C ชนิดค่า (struct, enum) ไม่รองรับ unowned เพราะพวกมันไม่มีส่วนร่วมใน ARC

เมื่อใด unowned ปลอดภัยกว่า weak?

เมื่อการรับประกันอายุสมบูรณ์และชัดเจน — unowned ปลอดภัยกว่าจากมุมมองการออกแบบ: ไม่ต้องการ unwrap, ไม่สามารถเป็น nil, และไม่ปิดบังข้อผิดพลาด หากออบเจ็กต์ไม่สามารถดำรงอยู่ได้โดยไม่มีพ่อแม่ unowned ทำให้มันเป็นสัญญาที่ชัดเจน ในขณะที่ weak ทำให้การรับประกันไม่ชัดเจน

มีประสิทธิภาพแตกต่างกันระหว่าง unowned และ weak หรือไม่?

ใช่: unowned เร็วกว่าเพราะไม่ต้องการเข้าถึงตาราง weak ขณะ运行时เพื่อทำให้เป็นศูนย์ ในแอปพลิเคชันส่วนใหญ่ความแตกต่างไม่รู้สึกได้ แต่ในสถานการณ์ที่มีโหลดสูงที่มีการเข้าถึงหลายล้านครั้ง unowned อาจเร็วกว่า 10–20% ในการอ่าน

การปรับโครงสร้างส่งผลต่อการรับประกันของ unowned อย่างไร?

การปรับโครงสร้าง เป็นอันตรายหลักสำหรับ unowned การเปลี่ยนอายุของออบเจ็กต์ (การแคช, การดำเนินการแบบอะซิงโครนัส, การใช้ซ้ำ) อาจทำลายการรับประกัน คอมไพเลอร์จะไม่เตือน วิธีแก้ไข: ย้ายไปใช้ weak เมื่อเปลี่ยนสถาปัตยกรรมหรือเพิ่มความคิดเห็นเตือน

สรุป

  • Unowned Reference — การอ้างอิงแบบไม่เป็นเจ้าของโดยไม่ทำให้เป็นศูนย์ ไม่จำเป็นต้องเลือก ไม่เพิ่ม retain count
  • การรับประกัน — ต้องการหลักฐานที่ชัดเจนว่าออบเจ็กต์มีอายุอย่างน้อยเท่ากับโค้ดที่อ้างอิงถึงมัน
  • ไวยากรณ์unowned let หรือ unowned var; สามารถเป็นแบบไม่เลือกและเลือกได้ (Swift 5.0+)
  • Unowned vs Weak — unowned เร็วกว่าและสะอาดกว่า แต่ weak ปลอดภัยกว่า weak เป็นตัวเลือกเริ่มต้น
  • Closures — unowned self เฉพาะสำหรับ closure แบบซิงโครนัส แบบอะซิงโครนัสต้องการ [weak self]
  • เอกสาร — แต่ละ unowned ต้องมีความคิดเห็นที่ให้เหตุผลในการรับประกัน
  • คำแนะนำ — เมื่อสงสัย ให้เลือก weak; unowned สำหรับสัญญาที่ชัดเจนและถูกบันทึกเป็นเอกสาร

เราจะพัฒนาแอปพลิเคชันบนมือถือแบบครบวงจร

IT Sectr สร้างแอปพลิเคชัน iOS และ Android สำหรับสตาร์ทอัพและธุรกิจตั้งแต่ปี 2017 เราจะให้คำแนะนำและเสนอวิธีแก้ปัญหาที่ดีที่สุดแก่คุณ

ปรึกษาโครงการ

อ่านเพิ่มเติม