푸시 컨트롤러에서 RootViewController를 어떻게 얻습니까?


137

그래서 RootViewController에서 다음과 같이 뷰 컨트롤러를 푸시합니다.

[self.navigationController pushViewController : anotherViewController animated : YES];

그러나 anotherViewController지금부터는 RootViewController에 다시 액세스하고 싶습니다.

노력하고있어

// (지금 anotherViewController 내부)
/// RootViewController * root = (RootViewController *) self.parentViewController; // 아니.
// 오류
RootViewController * root = (RootViewController *) [self.navigationController.viewControllers objectAtIndex : 0]; // 예!! 효과가있다

왜 이것이 효과가 있는지 잘 모르겠으며 최선의 방법인지 확실하지 않습니다. 누군가 당신이 RootViewController의 navigationController로 푸시 한 컨트롤러에서 RootViewController를 얻는 더 좋은 방법과 내가 한 방법이 신뢰할 수 있는지 여부에 대해 언급 할 수 있습니까?


"뒤로"보기 컨트롤러에 액세스하려면 루트보기 컨트롤러 (탐색 계층 구조의 첫 번째 컨트롤러)를 안정적으로 가져옵니다. 내 대답을 참조하십시오.
Ben S

답변:


133

UINavigationController 의 viewControllers 특성을 사용하십시오 . 예제 코드 :

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

이것이 "백"뷰 컨트롤러를 얻는 표준 방법입니다. objectAtIndex:0작동하려는 이유 는 액세스하려는 뷰 컨트롤러가 루트 컨트롤러이기도하기 때문입니다. 탐색이 더 깊다면 후면보기가 루트보기와 같지 않을 것입니다.


6
:) ty. 여전히 해키처럼 보인다-:) 나는 정말로 "공식적인"멤버가 self.navigationController.rootViewController와 같은 일을하기를 원했지만 아아, 그런 일은 없다 ..
bobobobo

62
위의 코드가 잘못되었습니다. rootViewController*전에 누락 되었으며 색인은이어야합니다 0. 문제의 코드는 정확합니다 :RootViewController *root = (RootViewController *)[navigationController.viewControllers objectAtIndex:0]
ma11hew28

2
동의 : 위의 코드는 OP가 요청한 루트 뷰 컨트롤러가 아닌 상위 뷰 컨트롤러를 반환합니다 . 그래도 벤 S가하겠다고 말한 것입니다. 그는 충분히 지적하지 않았습니다.
Ivan Vučica

두 번째 줄은 다음과 같아야합니다. UIViewController * rootViewController = [viewControllers objectAtIndex : viewControllers.count-1];
Billy

177

스위프트 버전 :

var rootViewController = self.navigationController?.viewControllers.first

ObjectiveC 버전 :

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

여기서 self는 UINavigationController에 포함 된 UIViewController의 인스턴스입니다.


다른 클래스에서 다른 ViewController의 navigationController를 얻을 수 있습니까?
sasquatch

모든 UIViewController 서브 클래스에는 navigationController 속성이 있으며, 이는 UINavigationController 클래스와 일치하는 첫 번째 parentViewController를 가리 킵니다.
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의 답변 외에도 항상 firstObjectover 를 사용하는 것이 좋습니다. objectAtIndex:0처음에는 배열에 객체가 없으면 nil을 반환하지만 후자는 예외를 throw하기 때문입니다.

UIViewController *rootViewController = self.navigationController.rootViewController;

또는 이름이 지정된 카테고리를 작성하고 해당 UINavigationController+Additions메소드를 정의 하는 것이 큰 장점 입니다.

@interface UINavigationController (Additions)

- (UIViewController *)rootViewController;

@end

@implementation UINavigationController (Additions)

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

@end

방금 답을 읽지 않고이 부분을 추가했습니다. "firstObject"가 더 나은 것입니다 [0]
dulgan

1

keyWindow에 대한 UIApplication 싱글 톤 을 요청 하고 UIWindow 에서 루트보기 컨트롤러 ( rootViewController 속성) 를 요청하는 방법은 무엇 입니까 ?

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

네비게이션 컨트롤러를 얻는 방법?
Yestay Muratov

내 응용 프로그램의 루트보기 컨트롤러가 UITabBarViewController 인 경우와 같이 잘못된 제안입니다.
Sandeep Singh Rana

1

여기서 나는 어디에서나 루트로 이동하는 보편적 인 방법을 생각해 냈습니다.

  1. 이 클래스를 사용하여 새 클래스 파일을 작성하면 프로젝트의 어느 곳에서나 액세스 할 수 있습니다.

    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.