อะไรคือความแตกต่างระหว่าง -viewWillAppear: และ -viewDidAppear:?


131

อะไรคือความแตกต่างระหว่าง-[UIViewController viewWillAppear:]และ-[UIViewController viewDidAppear:]?


1
ขอบคุณ BoltClock แต่โปรดยกตัวอย่างของทั้งสองอย่างถ้าเป็นไปได้ ..
PJR

3
@BoltClock คงจะดีถ้าเป็นเรื่องจริง ฉันเดาว่า 15 คนที่โหวตขึ้นมาอ่านชื่อวิธีการ แต่ไม่เคยวัดจริง ... มาที่นี่จาก Google เพราะนั่นไม่ใช่ความแตกต่างระหว่างพวกเขา
อดัม

1
โดยเฉพาะ: parentView.viewDidAppear เรียกว่า A LONG TIME ก่อนที่ Apple จะแสดง parentView จริง ... Apple ก่อน (atomically) จะวาดมุมมองย่อยทั้งหมด ... และถ้าคุณมีมุมมองย่อยจำนวนมากหรือซับซ้อน "viewDidAppear" สามารถเรียกได้ว่าเป็นหมื่น หรือหลายร้อยมิลลิวินาทีเร็วเกินไป :(.
อดัม

คำตอบ:


292

โดยทั่วไปนี่คือสิ่งที่ฉันทำ:

1) ViewDidLoad - เมื่อใดก็ตามที่ฉันเพิ่มการควบคุมไปยังมุมมองที่ควรปรากฏร่วมกับมุมมองทันทีฉันใส่ไว้ในเมธอด ViewDidLoad โดยทั่วไปจะเรียกวิธีนี้ทุกครั้งที่โหลดมุมมองลงในหน่วยความจำ ตัวอย่างเช่นหากมุมมองของฉันเป็นรูปแบบที่มีป้ายกำกับ 3 ป้ายฉันจะเพิ่มป้ายกำกับที่นี่ มุมมองจะไม่มีอยู่หากไม่มีรูปแบบเหล่านั้น

2) ViewWillAppear : ปกติฉันใช้ ViewWillAppear เพื่ออัปเดตข้อมูลในแบบฟอร์ม ดังนั้นตัวอย่างข้างต้นฉันจะใช้สิ่งนี้เพื่อโหลดข้อมูลจากโดเมนของฉันลงในแบบฟอร์ม การสร้าง UIViews นั้นค่อนข้างแพงและคุณควรหลีกเลี่ยงการทำเช่นนั้นบนเมธอด ViewWillAppear ให้มากที่สุดเพราะเมื่อสิ่งนี้ถูกเรียกนั่นหมายความว่า iPhone พร้อมที่จะแสดง UIView ให้กับผู้ใช้แล้วและสิ่งที่หนักหนาที่คุณทำที่นี่ จะส่งผลต่อประสิทธิภาพในลักษณะที่มองเห็นได้ชัดเจน (เช่นภาพเคลื่อนไหวล่าช้าเป็นต้น)

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


4
ขออภัยคุณ "โหลดข้อมูลจากโดเมนของฉันลงในแบบฟอร์ม" หมายความว่าviewWillAppearอย่างไร คุณหมายถึงการดาวน์โหลดผ่านเครือข่าย? แต่คุณยังแนะนำให้ดาวน์โหลดสิ่งต่างๆในviewDidAppear?
Philip007

1
@ Philip007 ผมคิดว่ากองจะหมายถึงประเภทของโดเมนนี้: en.wikipedia.org/wiki/Domain-specific_modeling ข้อมูลถูกโหลดจากรุ่นของคุณหรือรุ่นที่คล้ายกัน
dentarg

2
คำตอบนี้ควรอยู่ในเอกสาร มันมีประโยชน์มากในการชี้แจงความแตกต่างระหว่างสามวิธี ขอบคุณ!
GangstaGraham

1
+1 ฉันมีความสับสนเล็กน้อยในการทำความเข้าใจความแตกต่างระหว่างสามสิ่งนี้ แต่คุณเพิ่งเคลียร์มันมากกว่าที่สมบูรณ์แบบ @ChetanBhalara
Chisx

@ChetanBhalara แต่ถ้าคุณใช้เวลานานViewDidAppearคุณจะทำให้ผู้ใช้สับสนเกี่ยวกับ UI ได้อย่างง่ายดาย :)
hqt

46

viewDidLoad === >>> ใส่รหัสเริ่มต้นของคุณที่นี่ อย่าใส่ข้อมูลแบบไดนามิกที่อาจเปลี่ยนแปลงระหว่างวงจรการดู ดังนั้นหากคุณกำลังดึงข้อมูลจากข้อมูลหลักคุณไม่ต้องการทำที่นี่หากสิ่งนี้สามารถเปลี่ยนแปลงได้ในช่วงชีวิตของมุมมอง ตัวอย่างเช่นสมมติว่าคุณมีตัวควบคุมแท็บ คุณเปลี่ยนจาก tab1 เป็น tab2 และเปลี่ยนบางอย่างบนโมเดลใน tab2 หากคุณกลับมาที่ tab1 และรหัสโมเดลของคุณเสร็จสิ้นใน viewDidLoad สิ่งนี้จะไม่ถูกอัปเดต (สมมติว่าคุณไม่ได้ใช้ KVO หรือ NSFetchedResultsController เป็นต้น)

viewWillAppear === >>> สิ่งนี้ถูกเรียกทุกครั้งที่มุมมองกำลังจะปรากฏขึ้นไม่ว่ามุมมองนั้นจะอยู่ในหน่วยความจำแล้วหรือไม่ก็ตาม ใส่รหัสไดนามิกของคุณที่นี่เช่นตรรกะของโมเดล

viewDidAppear === >>> ใส่การดำเนินการที่มีราคาแพงที่นี่ที่คุณต้องการทำก็ต่อเมื่อคุณแน่ใจว่ามุมมองนั้นอยู่บนหน้าจอเช่นการโทรผ่านเครือข่าย

ข้อสังเกต: หากแอปของคุณเป็นพื้นหลังและกลับสู่เบื้องหน้าคุณต้องจัดการสิ่งนี้โดยใช้ NSNotificationCenter ฉันเขียนรหัสสำหรับสิ่งนั้นในความคิดเห็นด้านล่าง คุณอาจคิดว่า viewWillAppear / viewDidAppear จะเริ่มทำงาน วางจุดพักไว้ที่นั่นและทดสอบ มันไม่ยิง ดังนั้นหากแอปของคุณเปลี่ยนแปลงไปในขณะที่แอปอยู่เบื้องหลังคุณจะต้องอัปเดตโดยใช้การแจ้งเตือน


1
ViewWill หรือ ViewDid ทำงานทุกครั้งที่คุณยกเลิกการย่อขนาดแอปพลิเคชันหรือไม่
Jeef

2
@Jeef นี่เป็นคำถามที่ยอดเยี่ยม จะไม่ทำงานเว้นแต่ว่าแอปจะถูกฆ่าโดยระบบหรือผู้ใช้ขณะอยู่เบื้องหลัง สิ่งที่คุณต้องทำเพื่อรับการแจ้งเตือนเมื่อแอปไม่ได้ย่อขนาดคือคุณต้องใช้ NSNotificationCenter และ addObserver สำหรับชื่อ UIApplicationWillEnterForegroundNotification ตัวเลือกควรเป็น applicationWillEnterForeground: มีพารามิเตอร์ NSNotification ใส่รหัสของคุณในเมธอดนั้นเพื่อโหลดข้อมูลซ้ำ ฯลฯ สิ่งที่คุณทำได้คือสร้างเมธอดรีโหลดที่คุณเรียกจากเมธอดนี้และ viewDidAppear หากจำเป็นต้องเหมือนกัน
smileBot

2
@Jeef อะไรทำนองนี้: - (void) viewDidLoad {[[NSNotificationCenter defaultCenter] addObserver: self selector: @selector (applicationWillEnterForeground :) name: UIApplicationWillEnterForegroundNotification object: nil]; } - (โมฆะ) applicationWillEnterForeground: (NSNotification *) notif {//
response here with anything

12

viewWillAppearวิธีการที่เรียกว่าก่อนที่จะโหลดมุมมองที่เกิดขึ้นจริง

viewDidAppearวิธีการที่เรียกว่ามุมมองเมื่อมีการโหลดแล้วและคุณต้องการที่จะแสดงให้เห็นบางสิ่งบางอย่าง


9

viewWillAppear:
■เรียกก่อนที่มุมมองจะถูกเพิ่มไปยังลำดับชั้นมุมมองของ windows
■เรียกก่อน [vc.view layoutSubviews] (ถ้าจำเป็น)
viewDidAppear :
■เรียกว่าหลังจากเพิ่มมุมมองในลำดับชั้นของมุมมอง
■เรียกว่าหลังจาก [vc.view layoutSubviews] (ในกรณีที่จำเป็น)


7

ข้อสังเกตบางประการ:

  • viewDidLoadวิธีการที่เรียกว่าเมื่อมุมมองถูกสร้างครั้งแรก IBOutletการอ้างอิงจะเชื่อมโยงกันตามเวลาที่มีการเรียก แต่ไม่ใช่ก่อนหน้านี้ frameของมุมมองอาจไม่ได้รับการจัดตั้งขึ้นโดยเวลานี้ได้รับการเรียกว่า นี่เป็นสถานที่ที่ดีเยี่ยมในการเพิ่ม / กำหนดค่ามุมมองย่อยและข้อ จำกัด ที่เกี่ยวข้อง แต่ถ้าคุณกำลังทำสิ่งใดใช้การกำหนดค่าframeค่าบนพื้นฐานของมิติมุมมองหลักของการกำหนดค่าของเฟรมเหล่านั้นควรจะเลื่อนไปก่อนจนกว่าหรือviewWillAppearviewDidLayoutSubviews

  • viewWillAppearวิธีการที่เรียกว่าเมื่อนำเสนอมุมมองในลำดับชั้นมุมมองที่เป็นเรื่องเกี่ยวกับการเริ่มต้น สิ่งนี้เรียกว่าในช่วงเริ่มต้นของภาพเคลื่อนไหว (ถ้ามี) ของการนำเสนอของมุมมอง สหายของมันviewWillDisappearถูกเรียกอย่างชัดเจนเมื่อการเปลี่ยนจากมุมมองนี้เริ่มต้นขึ้น

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

คำเตือนที่สำคัญสองประการ:

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

    ดังนั้นถ้าคุณต้องการที่จะทำบางสิ่งบางอย่างทุกครั้งที่มีมุมมองที่ปรากฏขึ้นอีกครั้ง (เช่นคุณยกเลิกหรือป๊อปกลับไปมัน) ทำมันในหรือviewWillAppear หากคุณต้องการให้มันเกิดขึ้นเมื่อเพียงมุมมองถูกสร้างครั้งแรกที่ทำในviewDidAppearviewDidLoad

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

    ในงาน WWDC 2013 ในบริบทของการเปลี่ยนแบบโต้ตอบผู้นำเสนอพูดติดตลกว่าพวกเขาควรเปลี่ยนชื่อviewWillAppearเป็น " viewMightAppearหรือviewWillProbablyAppearหรือiReallyWishThisViewWouldAppear"

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

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


5

viewwillappear จะเรียกก่อนที่จะโหลดมุมมองเพื่อให้คุณสามารถทำงานบางอย่างได้ก่อนที่จะโหลดมุมมองนั้นและ viewdidappear จะเรียกหลังจากโหลดมุมมองดังนั้นงานโพสต์จะเสร็จสิ้นในวิธีนั้น


4

ความแตกต่างระหว่าง "will" และ "did" ... ตามชื่อที่แนะนำ viewWillAppear ถูกเรียกก่อนมุมมองกำลังจะปรากฏขึ้นและ viewDidAppear ถูกเรียกเมื่อมุมมองปรากฏขึ้น


ดูคำตอบที่ได้รับการยอมรับซึ่งมีการโหวตมากกว่า 70 รายการ :)
PJR

4

1) ViewWillAppear : มุมมองที่โหลดจริงในหน่วยความจำเรียกว่าหนึ่งครั้งในตัวควบคุมมุมมองและมีเฟรม แต่ยังไม่ปรากฏต่อผู้ใช้

2) ViewDidAppear : ตัวควบคุมที่เพิ่มเข้าไปในลำดับชั้นของมุมมองเพื่อให้คุณสามารถนำเสนอไปยังตัวควบคุมถัดไปได้นอกจากนี้มุมมองยังจัดวางมุมมองย่อย


3

อดีตเกิดขึ้นก่อนที่มุมมองจะปรากฏขึ้นและสิ่งหลังเกิดขึ้นในภายหลัง


3

สรุป:

-viewWillAppear -> อัปเดตข้อมูล (โหลดข้อมูลจากมุมมองตาราง)

-viewDidAppear -> การดำเนินการที่มีราคาแพง (การเรียก API ด้วยความคืบหน้าที่ดี!)


1

ตามชื่อที่แนะนำการviewWillAppearเรียกก่อนที่มุมมองจะปรากฏขึ้นและviewDidAppearถูกเรียกเมื่อมุมมองปรากฏขึ้น


0

Usecaseคือเมื่อไหร่ที่ควรใช้?

viewDidLoad - เมื่อป้ายกำกับปุ่ม (i, e ตัวควบคุม / มุมมองย่อยใด ๆ ) เชื่อมต่อกับไฟล์อินเทอร์เฟซของ View และหากคุณต้องการโหลดทั้งหมดเหล่านี้พร้อมกันกับ ViewController's View และหากคุณต้องการโหลดลงในหน่วยความจำเพียงครั้งเดียว ทำกับมัน

viewWillAppear- พูดว่าคุณต้องการเปลี่ยนสีพื้นหลังของมุมมองทุกครั้งที่ viewController ปรากฏบนหน้าจอ หรือสมจริงยิ่งขึ้นหากคุณต้องการสีพื้นหลัง DarkMode ในเวลากลางคืนของวันและสีอ่อนของมุมมองพื้นหลังในช่วงกลางวันให้ไปที่รหัสนี้ในviewWillAppear

อีกหนึ่ง usecase ดีๆที่นี่ https://stackoverflow.com/a/39395865/5438240

โปรดทราบว่าหากคุณใช้ Navigation stack ( UINavigationController) viewController ที่กำลังจะโผล่ขึ้นมาจะมีการviewWillDisappear()เรียกและ ViewController ที่ถัดไปจะอยู่ด้านบนของสแต็กจะviewWillAppear()เรียกว่า

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