เมื่อใดที่ฉันควรปล่อยวัตถุใน - (โมฆะ) viewDidUnload แทนที่จะเป็นใน -dealloc


103

อะไรคือสิ่งที่-(void)viewDidUnloadดี?

ฉันไม่สามารถเชื่อมโยงทุกอย่างได้-deallocหรือไม่? ถ้ามุมมองยกเลิกการโหลดจะไม่-deallocถูกเรียกใช่ไหม

คำตอบ:


51

-viewDidUnloadนอกเหนือไปจากสิ่งที่ได้รับการระบุไว้แล้วผมอยากจะอธิบายรายละเอียดเพิ่มเติมเกี่ยวกับตรรกะที่อยู่เบื้องหลัง

เหตุผลที่สำคัญที่สุดประการหนึ่งในการนำไปใช้คือUIViewControllerคลาสย่อยมักจะมีการอ้างอิงถึงมุมมองย่อยต่างๆในลำดับชั้นของมุมมอง คุณสมบัติเหล่านี้จะได้รับการตั้งค่าผ่านIBOutletsเมื่อโหลดจากปลายปากกาหรือโปรแกรมภายใน-loadViewเช่น

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

วัตถุที่คุณปล่อยที่นี่มักจะมีการสร้างและการตั้งค่าอีกครั้งเมื่อUIViewControllerมุมมองเป็นอย่างใดอย่างหนึ่งจากปลายปากกาหรือผ่านการดำเนินการของre-loaded-loadView

นอกจากนี้โปรดทราบว่าUIViewController viewสถานที่ให้บริการอยู่nilในเวลาที่เรียกวิธีนี้


1
คุณควรอ่านdeveloper.apple.com/library/ios/#featuredarticles/…เพื่อทำความเข้าใจวงจรชีวิตของตัวควบคุมมุมมอง / มุมมอง
Paul Solt

21

ตามเอกสารระบุว่า :

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

ในสถานการณ์เดียวกันdeallocจะไม่ถูกเรียก วิธีนี้ใช้ได้เฉพาะใน OS3 ขึ้นไป การรับมือกับสถานการณ์เดียวกันใน iPhone OS 2.x เป็นความเจ็บปวดอย่างแท้จริง!

อัปเดตกรกฎาคม 2015 : ควรสังเกตว่าviewDidUnloadเลิกใช้งานแล้วใน iOS 6 เนื่องจาก "มุมมองไม่ได้ถูกลบอีกต่อไปภายใต้สภาวะหน่วยความจำต่ำดังนั้นจึงไม่เรียกวิธีนี้" deallocดังนั้นคำแนะนำที่ทันสมัยไม่ได้ที่จะต้องกังวลเกี่ยวกับเรื่องนี้และการใช้งาน


6
นอกจากนี้จากเอกสาร: "คุณควรทำสิ่งนี้เฉพาะกับออบเจ็กต์ที่คุณสามารถสร้างขึ้นใหม่ได้อย่างง่ายดายในภายหลังไม่ว่าจะในเมธอด viewDidLoad ของคุณหรือจากส่วนอื่น ๆ ของแอปพลิเคชันของคุณคุณไม่ควรใช้วิธีนี้เพื่อเผยแพร่ข้อมูลผู้ใช้หรือข้อมูลอื่นใดที่ไม่สามารถ สร้างขึ้นใหม่ได้ง่าย ". นั่นเป็นคำถามที่ฉันเองก็มีเช่นกันขอบคุณ!
leolobato

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

ไม่คุณจะไม่ใช้สิ่งนี้หากคุณเพียงแค่สลับมุมมองหนึ่งไปเป็นอีกมุมมองหนึ่ง ลองนึกถึงกรณีที่คุณมี "สแต็ก" ของมุมมองที่มี UINavigationController มองเห็นได้เพียงมุมมองเดียวและหากคุณมีคำเตือนเกี่ยวกับหน่วยความจำคุณสามารถปล่อยมุมมองทั้งหมดที่มองไม่เห็นได้
Stephen Darlington

คุณจะควบคุมได้อย่างไรว่า viewDidUnload จะไม่ถูกเรียกในมุมมองที่มองเห็นได้ในปัจจุบันตามที่ขอขอบคุณ
arielcamus

1
viewDidUnload จะไม่ถูกเรียกในมุมมองที่มองเห็นได้ในปัจจุบันเฉพาะในมุมมองที่มองไม่เห็น
progrmr

9

เนื่องจากโดยทั่วไปคุณจะตั้งค่า@propertyเป็น"(nonatomic, retain)"และเป็นเช่นนั้นตัวตั้งค่าที่สร้างขึ้นเพื่อให้คุณเผยแพร่วัตถุปัจจุบันจากนั้นจะคงอาร์กิวเมนต์ไว้คือ

self.property = nil;

... ทำอะไรบางอย่างตามแนวของ:

[property release];
property = [nil retain];

ดังนั้นคุณจึงฆ่านกสองตัวด้วยหินก้อนเดียว: การจัดการหน่วยความจำ (ปล่อยวัตถุที่มีอยู่) และกำหนดตัวชี้เป็นศูนย์ (เนื่องจากการส่งข้อความใด ๆ ไปยังตัวชี้ศูนย์จะส่งกลับศูนย์)

หวังว่าจะช่วยได้


8

โปรดจำไว้ว่าviewDidUnloadเป็นวิธีการในตัวควบคุมมุมมองไม่ใช่ในมุมมอง มุมมองของ deallocวิธีการที่จะได้รับการเรียกเมื่อมุมมอง unloads แต่ควบคุมมุมมองของ deallocวิธีการอาจจะไม่ได้เรียกว่าจนกระทั่งต่อมา

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


ที่สมเหตุสมผล จะเกิดอะไรขึ้นถ้าฉันทิ้งตัวควบคุมมุมมองทั้งหมดไว้เสมอ นั่นคือสิ่งที่ฉันทำจริง ในกรณีนี้ฉันไม่ต้องจัดการกับ -viewDidUnload มากใช่ไหม? ฉันไม่เคยมีสถานการณ์ที่ฉันจะลดลงเฉพาะมุมมองเนื่องจากฉันมักจะทิ้งตัวควบคุมทั้งหมดหากมองไม่เห็นเลย
ขอบคุณ

แต่โปรดจำไว้ว่าในกรณีที่มุมมองของคุณกำลังแสดง แต่คุณมีมุมมองแบบเต็มหน้าจอเช่น ImagePicker อยู่ด้านบนมุมมองของคุณอาจถูกยกเลิกการโหลดแม้ว่าคุณจะไม่ได้วางแผนไว้ก็ตาม
David Maymudes

6

สรุป:

View Controllers มีคุณสมบัติมุมมอง โดยทั่วไปแล้วปลายปากกาหรือชิ้นส่วนของโค้ดจะเพิ่มมุมมองอื่น ๆ ให้กับมุมมองนี้ สิ่งนี้มักเกิดขึ้นภายในเมธอด -viewDidLoad เช่นนี้:

- (void)viewDidLoad {
    [super viewDidLoad];
    [self createManyViewsAndAddThemToSelfDotView];
}

นอกจากนี้ไฟล์ nib อาจสร้างปุ่มและต่อท้ายเข้ากับมุมมองของตัวควบคุมมุมมอง

บน iPhone OS 2.2 เมื่อเรียกใช้ -didReceiveMemoryWarning จากระบบคุณต้องปล่อยบางสิ่งเพื่อเพิ่มหน่วยความจำ คุณสามารถปล่อยมุมมองของตัวควบคุมมุมมองทั้งหมดได้หากเหมาะสม หรือเนื้อหาที่ใช้หน่วยความจำขนาดใหญ่ในนั้น

- (void)didReceiveMemoryWarning {
    [super didReceiveMemoryWarning]; // Releases the view if it doesn't have a superview
    // Release anything that's not essential, such as cached data
}

ตอนนี้ใน OS 3.0 ใหม่มีเมธอด -viewDidUnload ซึ่งจะเรียกใช้จากระบบเมื่อมุมมองถูกยกเลิกการโหลดเนื่องจากหน่วยความจำเหลือน้อย (โปรดแก้ไขฉัน: เมื่อใดที่สิ่งนี้ถูกเรียกว่า?)

-viewDidUnload ใช้เพื่อปล่อยอ็อบเจ็กต์ทั้งหมดที่เป็นของทั้งตัวควบคุมมุมมองและมุมมอง เหตุผล: หากตัวควบคุมมุมมองมีการอ้างอิงถึงชายด์ของมุมมองเช่นปุ่มมุมมองย่อยที่อ้างอิงจะไม่ถูกปล่อยเนื่องจากจำนวนการเก็บรักษาคือ> = 1 หลังจากที่ปล่อยใน -viewDidUnload พวกเขาจะได้รับอิสระ จากความทรงจำ.


1
การจำในมุมมองไม่ได้ยกเลิกการโหลดเพื่อทำ self.button = nil; ไม่ใช่ [ปล่อยปุ่ม];
mk12

6

Apple เลิกใช้ viewWillUnload ตอนนี้คุณใช้ didReceiveMemoryWarning หรือ dealloc เพื่อปล่อย objetcs ของคุณ

ใน iOS 6 เมธอด viewWillUnload และ viewDidUnload ของ UIViewController ได้เลิกใช้แล้ว หากคุณใช้วิธีการเหล่านี้เพื่อปล่อยข้อมูลให้ใช้เมธอด didReceiveMemoryWarning แทน คุณยังสามารถใช้วิธีนี้เพื่อปล่อยการอ้างอิงไปยังมุมมองของตัวควบคุมมุมมองหากไม่ได้ใช้ คุณจะต้องทดสอบว่ามุมมองไม่ได้อยู่ในหน้าต่างก่อนที่จะดำเนินการนี้


5

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


3

คุณสามารถเผยแพร่มุมมองย่อยใด ๆ ที่คุณมีอยู่เช่น UIImageView ที่คุณเก็บไว้ในเมธอด loadView หรือดีกว่า แต่รูปภาพที่อยู่บน UIImageView นั้น

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