ฉันจะรับ RootViewController จากคอนโทรลเลอร์ที่มีการพุชได้อย่างไร


137

ดังนั้นฉันดันดูควบคุมจาก RootViewController เช่น:

[self.navigationController pushViewController: anotherViewController เคลื่อนไหว: YES];

แต่anotherViewControllerตอนนี้ฉันต้องการเข้าถึง RootViewController อีกครั้ง

ฉันกำลังพยายาม

// (ข้างใน anotherViewController ทันที)
/// RootViewController * root = (RootViewController *) self.parentViewController; // ไม่ใช่
// ผิดพลาด
RootViewController * root = (RootViewController *) [self.navigationController.viewControllers objectAtIndex: 0]; // ใช่ !! มันได้ผล

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


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

คำตอบ:


133

ใช้คุณสมบัติviewControllersของ UINavigationController รหัสตัวอย่าง:

// Inside another ViewController
NSArray *viewControllers = self.navigationController.viewControllers;
UIViewController *rootViewController = [viewControllers objectAtIndex:viewControllers.count - 2];

นี่เป็นวิธีมาตรฐานในการรับตัวควบคุมมุมมอง "ย้อนกลับ" เหตุผลobjectAtIndex:0ก็เพราะตัวควบคุมมุมมองที่คุณพยายามเข้าถึงนั้นเป็นรูทตัวหนึ่งเช่นกันหากคุณอยู่ในการนำทางที่ลึกกว่ามุมมองด้านหลังจะไม่เหมือนกับมุมมองรูท


6
:) มันก็ยังคงดูเหมือน hacky - :) ผมอยากเป็นสมาชิก "อย่างเป็นทางการ" จริงๆที่จะทำผลงานได้บางอย่างเช่น self.navigationController.rootViewController แต่อนิจจาไม่มีสิ่งนั้น ..
bobobobo

62
รหัสด้านบนผิดพลาด rootViewControllerจะหายไปก่อนที่มันและดัชนีก็ควรจะเป็น* 0รหัสในคำถามนั้นถูกต้อง:RootViewController *root = (RootViewController *)[navigationController.viewControllers objectAtIndex:0]
ma11hew28

2
เห็นด้วย: รหัสดังกล่าวจะส่งกลับผู้ปกครองควบคุมดูไม่รากควบคุมดูเป็น OP ถาม ถึงกระนั้นนั่นก็คือสิ่งที่เบ็นเอสบอกว่าเขาจะทำเขาไม่ได้ชี้ให้เห็นว่าเพียงพอ
Ivan Vučica

บรรทัดที่ 2 ควรอ่าน: UIViewController * rootViewController = [viewControllers objectAtIndex: viewControllers.count - 1];
Billy

177

รุ่น Swift:

var rootViewController = self.navigationController?.viewControllers.first

เวอร์ชัน ObjectiveC:

UIViewController *rootViewController = [self.navigationController.viewControllers firstObject];

โดยที่ตัวเองเป็นตัวอย่างของ UIViewController ที่ฝังอยู่ใน UINavigationController


ฉันสามารถรับ navigationController ของ ViewController อื่นจากคลาสอื่นได้หรือไม่?
sasquatch

คลาสย่อย UIViewController ใด ๆ จะมีคุณสมบัติ navigationController ซึ่งชี้ไปที่ parentViewController แรกที่ตรงกับคลาส UINavigationController
dulgan

12

สิ่งเดียวกันกับรุ่นที่น่าเกลียดน้อยกว่าเล็กน้อยที่กล่าวถึงในคำตอบเหล่านี้ทั้งหมด:

UIViewController *rootViewController = [[self.navigationController viewControllers] firstObject];

ในกรณีของคุณฉันอาจทำสิ่งที่ชอบ:

ภายในคลาสย่อย UINavigationController ของคุณ :

- (UIViewController *)rootViewController
{
    return [[self viewControllers] firstObject];
}

จากนั้นคุณสามารถใช้:

UIViewController *rootViewController = [self.navigationController rootViewController];

แก้ไข

OP ขอคุณสมบัติในความคิดเห็น

หากคุณต้องการคุณสามารถเข้าถึงสิ่งนี้ได้self.navigationController.rootViewControllerโดยการเพิ่มคุณสมบัติแบบอ่านอย่างเดียวในส่วนหัวของคุณ:

@property (nonatomic, readonly, weak) UIViewController *rootViewController;

8

สำหรับทุกคนที่สนใจการขยายอย่างรวดเร็วนี่คือสิ่งที่ฉันกำลังใช้อยู่

extension UINavigationController {
    var rootViewController : UIViewController? {
        return self.viewControllers.first
    }
}

1
ขอบคุณ! นอกจากนี้คุณยังสามารถลบ "as? UIViewController"
atereshkov

3

นอกเหนือจากคำตอบของ @ dulganมันเป็นวิธีการที่ดีที่จะใช้firstObjectมากกว่าobjectAtIndex:0เพราะในขณะที่คนแรกส่งกลับศูนย์ถ้าไม่มีวัตถุในอาเรย์

UIViewController *rootViewController = self.navigationController.rootViewController;

หรือจะเป็นการดีสำหรับคุณในการสร้างหมวดหมู่ที่มีชื่อUINavigationController+Additionsและกำหนดวิธีการของคุณในนั้น

@interface UINavigationController (Additions)

- (UIViewController *)rootViewController;

@end

@implementation UINavigationController (Additions)

- (UIViewController *)rootViewController
{
    return self.viewControllers.firstObject;
}

@end

ฉันเพิ่งเพิ่มส่วนนี้โดยไม่ต้องอ่านคำตอบของคุณคุณมีสิทธิ์โดยสิ้นเชิงกับ "firstObject" ดีกว่า thant [0]
dulgan

1

วิธีการถามUIApplication singletonเกี่ยวกับkeyWindowและจากUIWindowนั้นขอตัวควบคุมมุมมองรูท ( คุณสมบัติrootViewController )

UIViewController root = [[[UIApplication sharedApplication] keyWindow] rootViewController];

วิธีรับตัวควบคุมทิศทาง
Yestay Muratov

นี่เป็นข้อเสนอแนะที่ไม่ถูกต้องเพราะจะเกิดอะไรขึ้นถ้าแอปพลิเคชัน rootviewcontroller ของฉันคือ UITabBarViewController
Sandeep Singh Rana

1

ฉันมาที่นี่ด้วยวิธีสากลเพื่อนำทางจากที่ใดก็ได้ไปที่รูต

  1. คุณสร้างไฟล์ Class ใหม่ด้วยคลาสนี้เพื่อให้สามารถเข้าถึงได้จากทุกที่ในโครงการของคุณ:

    import UIKit
    
    class SharedControllers
    {
        static func navigateToRoot(viewController: UIViewController)
        {
            var nc = viewController.navigationController
    
            // If this is a normal view with NavigationController, then we just pop to root.
            if nc != nil
            {
                nc?.popToRootViewControllerAnimated(true)
                return
            }
    
            // Most likely we are in Modal view, so we will need to search for a view with NavigationController.
            let vc = viewController.presentingViewController
    
            if nc == nil
            {
                nc = viewController.presentingViewController?.navigationController
            }
    
            if nc == nil
            {
                nc = viewController.parentViewController?.navigationController
            }
    
            if vc is UINavigationController && nc == nil
            {
                nc = vc as? UINavigationController
            }
    
            if nc != nil
            {
                viewController.dismissViewControllerAnimated(false, completion:
                    {
                        nc?.popToRootViewControllerAnimated(true)
                })
            }
        }
    }
  2. การใช้งานจากที่ใดก็ได้ในโครงการของคุณ:

    {
        ...
        SharedControllers.navigateToRoot(self)
        ...
    }

0

สิ่งนี้ใช้ได้กับฉัน:

เมื่อตัวควบคุมรูทมุมมองของฉันถูกฝังในตัวควบคุมทิศทาง:

UINavigationController * navigationController = (UINavigationController *)[[[[UIApplication sharedApplication] windows] firstObject] rootViewController];
RootViewController * rootVC = (RootViewController *)[[navigationController viewControllers] firstObject];

จำไว้ว่าkeyWindowเลิกใช้แล้ว

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