KVO และ ARC วิธีการเอาออก


87

คุณจะลบผู้สังเกตการณ์ออกจากวัตถุภายใต้ARC ได้อย่างไร? เราเพิ่งเพิ่มผู้สังเกตการณ์และลืมที่จะลบออกหรือไม่? ถ้าเราไม่จัดการหน่วยความจำด้วยตนเองอีกต่อไปเราจะลาออกจากการสังเกตการณ์ที่ไหน?

ตัวอย่างเช่นบนตัวควบคุมมุมมอง:

[self.view addObserver:self
            forKeyPath:@"self.frame"
               options:NSKeyValueObservingOptionNew 
               context:nil];

ก่อนหน้านี้ฉันจะเรียกremoveObserver:ด้วยdeallocวิธีของตัวควบคุมมุมมอง


4
โปรดทราบว่าเป็นความคิดที่ไม่ดีสำหรับ KVO .frame ตามที่เขียนไว้โดยวิศวกรของ Apple ใน StackOverflow คุณสมบัติเฟรมของ UIKit ไม่สอดคล้องกับ KVO เมื่อมันได้ผลมันเป็นเพียงความบังเอิญเท่านั้น
steipete

2
KeyPath ของคุณไม่ควรเป็น@"frame"มากกว่า@"self.frame"?
Besi

คำตอบ:


126

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

หากคุณเคยเอาชนะ-releaseมาก่อนแสดงว่าคุณกำลังทำสิ่งที่ผิด


1
คุณแน่ใจเกี่ยวกับเรื่องนี้หรือไม่? ฉันอ้างจากclang.llvm.org/docs/…ส่วน 7.1.2 dealloc: "เหตุผล: แม้ว่า ARC จะทำลายตัวแปรอินสแตนซ์โดยอัตโนมัติ แต่ก็ยังมีเหตุผลที่ถูกต้องในการเขียนเมธอด dealloc เช่นการปลดปล่อยทรัพยากรที่ไม่สามารถเก็บรักษาได้การไม่เรียก [super dealloc] ในวิธีดังกล่าวมักเป็นข้อบกพร่อง"
Elise van Looij

@ElisevanLooij ใช่เป็นเรื่องจริง [super dealloc]ถ้าคุณมาจากชั้นนี้ดูเหมือนว่าเห็นได้ชัดว่าคุณต้องเรียก ใครควรทำสิ่งนี้ให้คุณ
Björn Landmesser

@ElisevanLooij อ๊ะน่าจะตรวจสอบก่อนนะ ไม่อนุญาตให้โทร[super dealloc]ด้วยวิธี dealloc ไม่รู้ว่าสิ่งนี้จะทำงานอย่างไรเมื่อจัดคลาสย่อยของคลาสที่กล่าวถึง บางทีขอแนะนำให้ใช้finalizeแทน (ที่คุณโทร[super finalize])
Björn Landmesser

17
@ElisevanLooij - ประเด็นที่พวกเขาพยายามทำให้มีเกี่ยวกับกรณีการจัดการหน่วยความจำแบบแมนนวล เนื่องจากการไม่โทร[super dealloc]ครั้งสุดท้ายในวิธีนั้นมักจะเป็นข้อผิดพลาดภายใต้การจัดการหน่วยความจำด้วยตนเองคอมไพเลอร์จะจัดการให้คุณในตอนนี้ซึ่งเป็นสาเหตุที่คุณไม่สามารถโทร-deallocโดยตรงได้อีกต่อไป สิ่งเดียวที่คุณใส่ใน-deallocวิธีการภายใต้ ARC คือทรัพยากรที่ไม่ใช่วัตถุที่คุณต้องการเพื่อให้ว่างหรือล้างงานต่างๆเช่นการลบผู้สังเกตการณ์ ถ้อยคำที่พวกเขาใช้เป็นเพียงโคลนเล็กน้อย แต่นี่คือสิ่งที่พวกเขาหมายถึง
Brad Larson

7
@ BjörnMilcke - ขณะที่ฉันแสดงความคิดเห็นเกี่ยวกับคำตอบของ Elise -finalizeถูกนำมาใช้ในการเก็บขยะซึ่ง-deallocไม่เคยถูกเรียก แต่เป็นที่ยอมรับอย่างสมบูรณ์ในการวางรหัสนี้ไว้-deallocภายใต้ ARC [super dealloc]ถูกเรียกหาคุณโดยอัตโนมัติซึ่งเป็นเหตุผลว่าทำไมจึงเป็นข้อผิดพลาดที่จะเรียกมันภายใต้ ARC
Brad Larson

1

ฉันใช้รหัสนี้

- (void)dealloc
{
@try{
    [self.uAvatarImage removeObserver:self forKeyPath:@"image" context:nil];
} @catch(id anException) {
    //do nothing, obviously it wasn't attached because an exception was thrown
}
}    

2
การจัดการข้อยกเว้นdeallocคืออะไร? สายเกินไปที่จะทำอะไรกับมัน
Abizern

อะไรคือจุดของการลบผู้สังเกตการณ์ในตัวแปรอินสแตนซ์ใน dealloc? uAvatarImage นี้จะถูกยกเลิกการจัดสรรในไม่ช้าพร้อมกับผู้สังเกตการณ์ที่สมัครรับเส้นทางหลัก
shoumikhin

1
@shoumikhin ฉันใช้ ARC และฉันต้องลบผู้สังเกตการณ์ด้วยวิธี dealloc ฉันมีคำถามเดียวกันกับคุณ อย่างไรก็ตามเมื่อฉันรันหลายอินสแตนซ์ของคลาสในที่สุดฉันก็ได้รับข้อผิดพลาด exc_bad_address การทำเช่นนี้ช่วยแก้ปัญหาได้ นอกจากนี้คำตอบจากที่นี่stackoverflow.com/questions/32490808/…ช่วยให้ฉันค้นพบปัญหา
mac10688

-2

ที่อื่นบนสแตกล้น Chris Hanson แนะนำให้ใช้วิธีการสรุปเพื่อจุดประสงค์นี้และใช้วิธีการที่ไม่ถูกต้องแยกต่างหากเพื่อให้เจ้าของสามารถบอกออบเจ็กต์ว่าเสร็จสิ้นแล้ว ที่ผ่านมาฉันพบว่าวิธีแก้ปัญหาของแฮนสันมีการไตร่ตรองอย่างดีดังนั้นฉันจะดำเนินการต่อไป


13
โปรดทราบว่าเขาอ้างถึงการเก็บขยะที่นั่นไม่ใช่ ARC (คำตอบของเขาเขียนเมื่อปี 2008) ภายใต้การเก็บขยะ-deallocไม่เคยถูกเรียก ใน ARC ก็คือ การลบผู้สังเกตการณ์ KVO ออกเป็นเรื่องที่ยอมรับได้อย่างสมบูรณ์-deallocเนื่องจาก Chris Lattner (ผู้ที่รู้ว่าเขากำลังพูดถึงอะไร) ระบุไว้ในฟอรัมนักพัฒนาของ Apple ที่นี่: devforums.apple.com/message/475850
Brad Larson

3
ขอบคุณแบรดที่ทำงานทั้งหมดนี้ ไม่ต้องสรุปใช่สำหรับ dealloc แต่ไม่มี [super dealloc] ง่ายจริง ๆ เมื่อคุณรู้แล้ว เฮ้ @drunknbass ยอมรับคำตอบของผู้ชายคนนั้น!
Elise van Looij
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.