dealloc ใน Swift


145

ฉันต้องการดำเนินการล้างข้อมูลเมื่อสิ้นสุดอายุการใช้งานของวิวคอนโทรลเลอร์คือลบการNSNotificationCenterแจ้งเตือน การใช้deallocผลลัพธ์ในข้อผิดพลาดของคอมไพเลอร์ Swift:

Cannot override 'dealloc' which has been marked unavailable

อะไรคือวิธีที่ดีที่สุดในการทำความสะอาดบางอย่างเมื่อสิ้นสุดชีวิตของวัตถุใน Swift

คำตอบ:


333
deinit {
    // perform the deinitialization
}

จากเอกสาร Swift :

deinitializer ถูกเรียกใช้ทันทีก่อนที่คลาสอินสแตนซ์จะถูกจัดสรรคืน คุณเขียน deinitializers ด้วยคีย์เวิร์ด deinit ซึ่งคล้ายกับวิธีเขียนด้วยคำว่า intializers ด้วยคำสำคัญ init Deinitializers มีเฉพาะในชั้นเรียนเท่านั้น

โดยทั่วไปคุณไม่จำเป็นต้องทำการล้างด้วยตนเองเมื่ออินสแตนซ์ของคุณถูกจัดสรรคืน อย่างไรก็ตามเมื่อคุณทำงานกับทรัพยากรของคุณเองคุณอาจต้องทำความสะอาดเพิ่มเติมด้วยตัวเอง ตัวอย่างเช่นหากคุณสร้างคลาสที่กำหนดเองเพื่อเปิดไฟล์และเขียนข้อมูลลงไปคุณอาจต้องปิดไฟล์ก่อนที่อินสแตนซ์ของคลาสจะถูกจัดสรรคืน


45
deinit {
    // perform the deinitialization
}

เป็นคำตอบที่ถูกต้องสำหรับ Swift "dealloc"

อย่างไรก็ตามเป็นการดีที่จะชี้ให้เห็นใหม่ใน iOS 9 ที่ NSNotificationCenter ไม่จำเป็นต้องทำความสะอาดอีกต่อไป!

https://developer.apple.com/library/content/releasenotes/Foundation/RN-FoundationOlderNotes/index.html#X10_11Notes

NSNotificationCenter

ใน OS X 10.11 และ iOS 9.0 NSNotificationCenter และ NSDistributedNotificationCenter จะไม่ส่งการแจ้งเตือนไปยังผู้สังเกตการณ์ที่ลงทะเบียนอีกต่อไปซึ่งอาจถูกจัดสรรคืน หากผู้สังเกตการณ์สามารถจัดเก็บเป็นข้อมูลอ้างอิงศูนย์ zero-อ่อนแอหน่วยเก็บข้อมูลพื้นฐานจะเก็บผู้สังเกตการณ์เป็นศูนย์อ้างอิงอ่อนหรือถ้าวัตถุไม่สามารถจัดเก็บอย่างอ่อนแอ (เช่นมีกลไกรักษา / ปล่อยที่กำหนดเองที่จะป้องกันไม่ให้รันไทม์ จากความสามารถในการจัดเก็บวัตถุอย่างอ่อน) มันจะจัดเก็บวัตถุเป็นการอ้างอิง zeroing ที่ไม่อ่อนแอ ซึ่งหมายความว่าผู้สังเกตการณ์ไม่จำเป็นต้องยกเลิกการลงทะเบียนในวิธีการจัดสรรคืน การแจ้งเตือนครั้งต่อไปที่จะถูกส่งไปยังผู้สังเกตการณ์นั้นจะตรวจจับการอ้างอิงที่เป็นศูนย์และยกเลิกการลงทะเบียนผู้สังเกตการณ์โดยอัตโนมัติ หากวัตถุที่สามารถอ้างอิงการแจ้งเตือนอย่างอ่อนจะไม่ถูกส่งไปยังผู้สังเกตการณ์ในระหว่างการยกเลิกการจัดสรร พฤติกรรมก่อนหน้านี้ของการรับการแจ้งเตือนระหว่างการ dealloc ยังคงปรากฏอยู่ในกรณีที่ผู้สังเกตการณ์อ้างอิงที่ไม่เป็นศูนย์อย่างอ่อน ปิดกั้นผู้สังเกตการณ์ผ่านทาง - [NSNotificationCenter addObserverForName: object: que: usingBlock] วิธีการยังคงต้องยกเลิกการลงทะเบียนเมื่อไม่ได้ใช้งานอีกต่อไปเนื่องจากระบบยังคงมีการอ้างอิงที่แข็งแกร่งกับผู้สังเกตการณ์เหล่านี้ การถอดผู้สังเกตการณ์ (ทั้งที่อ้างอิงน้อยหรือเป็นศูนย์อ้างอิง) ยังคงได้รับการสนับสนุนก่อนกำหนด CFNotificationCenterAddObserver ไม่สอดคล้องกับลักษณะการทำงานนี้เนื่องจากผู้สังเกตอาจไม่ใช่วัตถุ ปิดกั้นผู้สังเกตการณ์ผ่านทาง - [NSNotificationCenter addObserverForName: object: que: usingBlock] วิธีการยังคงต้องยกเลิกการลงทะเบียนเมื่อไม่ได้ใช้งานอีกต่อไปเนื่องจากระบบยังคงมีการอ้างอิงที่แข็งแกร่งกับผู้สังเกตการณ์เหล่านี้ การถอดผู้สังเกตการณ์ (ทั้งที่อ้างอิงน้อยหรือเป็นศูนย์อ้างอิง) ยังคงได้รับการสนับสนุนก่อนกำหนด CFNotificationCenterAddObserver ไม่สอดคล้องกับลักษณะการทำงานนี้เนื่องจากผู้สังเกตอาจไม่ใช่วัตถุ ปิดกั้นผู้สังเกตการณ์ผ่านทาง - [NSNotificationCenter addObserverForName: object: que: usingBlock] วิธีการยังคงต้องยกเลิกการลงทะเบียนเมื่อไม่ได้ใช้งานอีกต่อไปเนื่องจากระบบยังคงมีการอ้างอิงที่แข็งแกร่งกับผู้สังเกตการณ์เหล่านี้ การถอดผู้สังเกตการณ์ (ทั้งที่อ้างอิงน้อยหรือเป็นศูนย์อ้างอิง) ยังคงได้รับการสนับสนุนก่อนกำหนด CFNotificationCenterAddObserver ไม่สอดคล้องกับลักษณะการทำงานนี้เนื่องจากผู้สังเกตอาจไม่ใช่วัตถุ

แต่ให้สังเกตจุดด้านล่างเกี่ยวกับการอ้างอิงที่แข็งแกร่งดังนั้นคุณอาจต้องกังวลเกี่ยวกับการล้างข้อมูลต่อไป ... ?


3
ยกเว้นว่าบล็อกการแจ้งเตือนมีการอ้างอิงที่รัดกุมคุณต้องลบผู้สังเกตการณ์ออก
TigerCoding

+1 สำหรับไม่ต้องล้างข้อมูลผู้สังเกตการณ์ สำคัญที่ต้องรู้! ฉันทำให้การอ้างอิงทั้งหมดอ่อนแอดังนั้นจึงไม่ต้องจัดการกับเรื่องนี้
n13

2
บล็อกการแจ้งเตือนดูเหมือนจะมีการอ้างอิงอย่างมากตามเอกสาร ดังนั้น: หากคุณกำลังใช้บล็อกเพื่อจัดการการแจ้งเตือนของคุณคุณจะต้องยกเลิกการลงทะเบียนสำหรับพวกเขาภายใน deinit
marsbear

22

https://developer.apple.com/library/content/documentation/Swift/Conceptual/Swift_Programming_Language/Deinitialization.html

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

คำจำกัดความของคลาสสามารถมี deinitializer ได้สูงสุดหนึ่งรายการต่อคลาส deinitializer ไม่ใช้พารามิเตอร์ใด ๆ และเขียนโดยไม่มีวงเล็บ:

deinit {
    // perform the deinitialization
}

2

จำเป็นต้องลบผู้สังเกตการณ์ก่อนการจัดสรรคืนมิฉะนั้นจะเกิดความผิดพลาด มันสามารถทำได้โดยใช้

deinit {
    // perform the deinitialization
    print("deinit")

    removeObserver(self, forKeyPath: kSelectedViewControllerKey, context: nil)
    removeObserver(self, forKeyPath: kSelectedIndexKey, context: nil)

}

-2

ระวังเมื่อเรียกวิธีการในคลาสอื่น ๆ จากdeinitมันอาจจะจบลงด้วยความผิดพลาด


1
ลงคะแนนว่าไม่ควรจำเป็น จากการอ้างอิง เอกสาร : เนื่องจากอินสแตนซ์ไม่ได้ถูกจัดสรรคืนจนกว่าจะมีการเรียก deinitializer deinitializer จึงสามารถเข้าถึงคุณสมบัติทั้งหมดของอินสแตนซ์ที่ถูกเรียกใช้และสามารถปรับเปลี่ยนพฤติกรรมตามคุณสมบัติเหล่านั้น (เช่นค้นหาชื่อของไฟล์ที่ต้องการ ถูกปิด)
superjos
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.