View Controller Containment ทำงานอย่างไรใน iOS 5


108

ในงาน WWDC 2011 เซสชัน 102, Apple เปิดดูควบคุมกักกันซึ่งเป็นความสามารถในการสร้างมุมมองที่กำหนดเองภาชนะควบคุมคล้ายคลึงกับUITabBarController, UINavigationControllerและไม่ชอบ

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

สถานการณ์ที่ 1: การย้ายจากผู้ปกครองไปยังตัวควบคุมมุมมองหลักใหม่

[vc willMoveToParentViewController:self];
[self addChildViewController:vc];
[self.view addSubview:vc.view]; // or something like this.
[vc didMoveToParentViewController:self];

สองบรรทัดแรกต้องเกิดขึ้นตามลำดับที่กำหนดหรือสามารถย้อนกลับได้หรือไม่?

สถานการณ์ที่ 2: การย้ายจากตัวควบคุมมุมมองหลักไปยังไม่มีตัวควบคุมมุมมองหลัก

[vc willMoveToParentViewController:nil];
[vc.view removeFromSuperview];
[vc removeFromParentViewController];

ยังจำเป็นต้องโทร[vc didMoveToParentViewController:nil]? ตัวอย่างในเซสชัน 102 ไม่ได้ทำสิ่งนี้ในสถานการณ์นี้ แต่ฉันไม่รู้ว่านั่นเป็นการละเว้นหรือไม่

สถานการณ์ที่ 3: การย้ายจากตัวควบคุมมุมมองหลักไปยังอีกตัวหนึ่ง

สิ่งนี้อาจเกิดขึ้นในลักษณะต่อไปนี้เนื่องจากตรรกะในตัวควบคุมมุมมองหลักแต่ละตัวจะถูกห่อหุ้ม

// In the old parent
[vc willMoveToParentViewController:nil];
[vc.view removeFromSuperview];
[vc removeFromParentViewController];

// In the new parent
[vc willMoveToParentViewController:self];
[self addChildViewController:vc];
[self.view addSubview:vc.view];
[vc didMoveToParentViewController:self];

คำถาม

คำถามหลักของฉันคือ: โดยทั่วไปแล้วการควบคุมมุมมองควรทำงานอย่างไร กลไกที่ระบุข้างต้นถูกต้องหรือไม่?

willMoveToParentViewControllerก่อนโทรจำเป็นaddChildViewControllerหรือไม่? นี่ดูเหมือนจะเป็นคำสั่งทางตรรกะสำหรับฉัน แต่มันจำเป็นอย่างยิ่งหรือไม่?

didMoveToParentViewController:nilหลังโทรจำเป็นremoveFromParentViewControllerไหม?

คำตอบ:


72

UIViewControllerเอกสารจะสวยชัดเจนเมื่อและเมื่อไม่โทรwillMove/ didMoveวิธีการ ตรวจสอบ"การนำตู้คอนเทนเนอร์ดูควบคุม"เอกสาร

เอกสารบอกว่าถ้าคุณไม่ลบล้างaddChildViewControllerคุณไม่ต้องเรียก willMoveToParentViewController:เมธอด อย่างไรก็ตามคุณจำเป็นต้องเรียกใช้didMoveToParentViewController:เมธอดหลังจากการเปลี่ยนแปลงเสร็จสมบูรณ์ "ในทำนองเดียวกันเป็นความรับผิดชอบของตัวควบคุมมุมมองคอนเทนเนอร์ในการเรียกใช้willMoveToParentViewController:เมธอดก่อนที่จะเรียกใช้removeFromParentViewControllerเมธอดremoveFromParentViewControllerเมธอดจะเรียกdidMoveToParentViewController:เมธอดของตัวควบคุมมุมมองเด็ก"

นอกจากนี้ยังมีตัวอย่างออกไปทำงานที่นี่และรหัสตัวอย่างที่นี่

โชคดี


17
ผมเห็นดังนั้นaddChildViewControllerควรมีความสมดุลด้วยdidMoveToParentViewControllerและควรมีความสมดุลกับwillMoveToParentViewController removeFromParentViewControllerนี่คือสิ่งที่ฉันกำลังมองหา ไม่แน่ใจว่าฉันพลาดในเอกสารนี้ไปได้อย่างไร
Gregory Higley

ทำไมจะไม่ล่ะ? ทำไมคุณไม่ต้องเรียก willMoveToParentViewController แต่แฮเรียก didMoveToParentViewController?
user4951

เพราะนั่นคือสิ่งที่เอกสารบอก เห็นได้ชัดว่า Apple รู้สึกว่าเราไม่จำเป็นต้องรู้

7
เหตุผลก็เพื่อประโยชน์ของแอนิเมชั่น: สมมติว่าคุณกำลังสร้างตัวควบคุมการนำทางของคุณเอง ในช่วงเริ่มต้นของภาพเคลื่อนไหวแบบสไลด์เข้าจำเป็นต้องเรียก "willMove" และในตอนท้ายของภาพเคลื่อนไหวจะต้องเรียก "didMove" ตอนนี้เมื่อคุณเรียก 'addChild' ที่จุดเริ่มต้นของภาพเคลื่อนไหวระบบจะเรียก 'willMove' ให้คุณโดยอัตโนมัติ แต่ไม่สามารถรู้ได้ว่าเมื่อใดที่ภาพเคลื่อนไหว (หากมี) เสร็จสิ้นดังนั้นคุณต้องเรียก "didMove" ด้วยตนเองเมื่อสิ้นสุดภาพเคลื่อนไหว (หรือทันทีที่ไม่มีภาพเคลื่อนไหว)
คริส

2
และสำหรับภาพเคลื่อนไหว "เลื่อนออก" เช่นเด็กกำลังถูกลบคุณต้องเรียก "willMove" ด้วยตนเองเมื่อเริ่มต้นภาพเคลื่อนไหวเนื่องจาก uikit จะไม่รู้ว่าเมื่อใดควรเรียก 'viewWillDisappear' ของ VC ของลูกของคุณ และในตอนท้ายของภาพเคลื่อนไหวเมื่อคุณเรียก removeFromParentViewController มันสามารถเรียก 'didMove' ให้คุณโดยอัตโนมัติ
คริส

23

ส่วนนี้ไม่ถูกต้อง:

[vc willMoveToParentViewController:self];
[self addChildViewController:vc];
[self.view addSubview:vc.view]; // or something like this.
[vc didMoveToParentViewController:self];

ตามเอกสาร:

เมื่อคอนเทนเนอร์แบบกำหนดเองของคุณเรียกใช้เมธอด addChildViewController: มันจะเรียกเมธอด willMoveToParentViewController: ของตัวควบคุมมุมมองโดยอัตโนมัติเพื่อเพิ่มเป็นลูกก่อนที่จะเพิ่ม

ดังนั้นคุณไม่จำเป็นต้อง[vc willMoveToParentViewController:self]โทร [self addChildViewController:vc]มันจะทำโดยอัตโนมัติเมื่อคุณเรียก นี่คือตัวอย่างโค้ดอีกครั้ง:

[self addChildViewController:vc];
// [vc willMoveToParentViewController:self] called automatically
[self.view addSubview:vc.view]; // or something like this.
[vc didMoveToParentViewController:self];

สำหรับการลบตัวควบคุมมุมมอง:

เมธอด removeFromParentViewController จะเรียกเมธอด didMoveToParentViewController: เมธอดของตัวควบคุมมุมมองเด็กโดยอัตโนมัติหลังจากที่มันลบเด็กออก

[oldVC didMoveToParentViewController:nil]สันนิษฐานว่าสายนี้คือ

[vc willMoveToParentViewController:nil];
[vc.view removeFromSuperview];
[vc removeFromParentViewController];
// [vc didMoveToParentViewController:nil] called automatically

ดูเหมือนว่าถ้าทำอย่างอื่นแม้ว่ามันจะใช้งานได้ แต่ก็ไม่ได้ตั้งค่า PresentationViewController ในการนำเสนอViewController
Adrian

เอกสารบอกว่าโทรdidMoveToParentViewController " ทันทีหลังจากเรียก addChildViewController: method" จะไม่ระบุเวลาที่คุณเพิ่มมุมมองย่อยลูกจริงๆ ฉันสงสัยว่าทุกคนเข้าใจผิดหรือเปล่า มีตัวอย่างในเอกสารของ Apple ที่เราสามารถตรวจสอบได้หรือไม่?
Robert

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