dealloc ที่กำหนดเองและ ARC (Objective-C)


208

ในแอพ iPad เล็ก ๆ ของฉันฉันมีฟังก์ชั่น "เปลี่ยนภาษา" ที่ใช้ผู้สังเกตการณ์ viewDidLoad:ทุกควบคุมดูลงทะเบียนตัวเองกับผู้สังเกตการณ์ของฉันในช่วงของ

- (void)viewDidLoad
{
    [super viewDidLoad];
    [observer registerObject:self];
}

เมื่อผู้ใช้กดปุ่ม "เปลี่ยนภาษา" ภาษาใหม่จะถูกเก็บไว้ในรูปแบบของฉันและผู้สังเกตการณ์จะได้รับแจ้งและเรียกupdateUi:ตัวเลือกบนวัตถุที่ลงทะเบียน

สิ่งนี้ทำงานได้ดีมากยกเว้นเมื่อฉันมีตัวควบคุมมุมมองใน TabBarController นี่คือเนื่องจากเมื่อแถบแท็บโหลดมันดึงไอคอนแท็บจากตัวควบคุมลูกโดยไม่ต้องเริ่มต้นมุมมองดังนั้นจึงviewDidLoad:ไม่ถูกเรียกดังนั้นตัวควบคุมมุมมองเหล่านั้นไม่ได้รับการแจ้งเตือนการเปลี่ยนแปลงภาษา ด้วยเหตุนี้ฉันจึงย้ายการregisterObject:โทรไปยังinitวิธีการ

ย้อนกลับไปเมื่อฉันเคยviewDidLoad:ลงทะเบียนกับผู้สังเกตการณ์ฉันเคยviewDidUnload:ยกเลิกการลงทะเบียน ตั้งแต่ตอนนี้ผมลงทะเบียนในก็จะทำให้ความรู้สึกมากที่จะถอนการลงทะเบียนในinitdealloc

แต่นี่คือปัญหาของฉัน เมื่อฉันเขียน:

- (void) dealloc
{
    [observer unregisterObject:self];
    [super dealloc];
}

ฉันได้รับข้อผิดพลาดนี้:

ARC ห้ามส่งข้อความที่ชัดเจนถึง 'dealloc'

เนื่องจากฉันต้องโทรหา[super dealloc]เพื่อให้แน่ใจว่าซูเปอร์คลาสนั้นสะอาดอย่างถูกต้อง แต่ ARC ห้ามไม่ให้ฉันติดอยู่ตอนนี้ มีวิธีอื่นที่จะได้รับแจ้งเมื่อวัตถุของฉันใกล้จะตายหรือไม่


หมายเหตุด้านข้าง - สถานการณ์เช่นนี้อาจทำให้หน่วยความจำรั่วซึ่งจะไม่แสดงในเครื่องมือการรั่วไหล หาก dataModel เก็บการอ้างอิงไปยังผู้สังเกตการณ์ (ซึ่งเป็นสิ่งที่เป็นค่าเริ่มต้นภายใต้ ARC แม้แต่สำหรับ ivars) dealloc จะไม่ถูกเรียกใช้เนื่องจากการนับการเก็บรักษาจะมากกว่าศูนย์ ดังนั้นคุณอาจต้องยกเลิกการลงทะเบียนผู้สังเกตการณ์ด้วยตนเองเพื่อให้สามารถเรียกใช้ dealloc ได้ในตอนแรก
Błażej Czapp

ฉันใช้สิ่งที่คล้ายกันสำหรับตัวเลือกมือขวาและมือซ้าย VC เดียวที่ต้องการข้อความคือสิ่งที่แสดงในปัจจุบัน คนอื่นดูที่โมเดลใน viewDidLoad หรือ viewDidAppear เพื่อทำการเปลี่ยนแปลงอินเทอร์เฟซ บางทีสิ่งนี้จะทำงานได้ดีขึ้น
Doug Watkins

@BlazejCzapp เนื่องจากเขาใช้ UITabBarController และสมมติว่า UITabBarController มักจะมีการอ้างอิงถึงตัวควบคุมที่ลงทะเบียนเสมอ (เพราะฉันเดาว่าเป็นกรณีที่มีตัวควบคุม 'เด็ก') หน่วยความจำรั่วจะยังเป็นปัญหาหรือไม่ ฉันไม่เห็นว่าจะจัดสรรคอนโทรลเลอร์ที่ลงทะเบียนเมื่อใด ขอบคุณ
Objectif

คำตอบ:


419

เมื่อใช้ ARC คุณไม่ต้องเรียก[super dealloc]อย่างชัดเจน - คอมไพเลอร์จัดการให้คุณ (ดังอธิบายในเอกสารClang LLVM ARC ตอนที่ 7.1.2 ):

- (void) dealloc
{
    [observer unregisterObject:self];
    // [super dealloc]; //(provided by the compiler)
}

4
ถ้า view เก็บการอ้างอิงไปยังผู้สังเกตการณ์และผู้สังเกตการณ์เก็บการอ้างอิงไปยังมุมมองเราจะมีการอ้างอิงแบบวงกลม ดังนั้นจำนวนการอ้างอิงของมุมมองมากกว่า 0 และdeallocไม่เคยถูกเรียก มันเหมาะสมแล้วที่จะโทรหา[observer unregisterObject:self]dealloc? ฉันพลาดอะไรไป
user443854

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