programing

푸시된 컨트롤러에서 루트뷰 컨트롤러를 가져오려면 어떻게 해야 합니까?

newstyles 2023. 6. 13. 22:03

푸시된 컨트롤러에서 루트뷰 컨트롤러를 가져오려면 어떻게 해야 합니까?

RootViewController에서 다음과 같은 보기 컨트롤러를 푸시합니다.

[self.navigationController pushViewController: 다른 ViewController 애니메이션:예];

그러나, 시작anotherViewController이제 RootView 컨트롤러에 다시 액세스하려고 합니다.

난 노력하고 있어.

(지금 다른 View 컨트롤러 내부)///RootViewController *root = (RootViewController*)self.parentViewController ; // 아니요.잘못한RootViewController *root = (RootViewController*)[self.navigationController.viewController 개체 At색인:0] ; // YES!!그건 효과가 있다.

저는 이것이 왜 효과가 있는지 그리고 그것을 하는 가장 좋은 방법인지 확신할 수 없습니다.RootViewController의 탐색 컨트롤러에 푸시한 컨트롤러에서 RootViewController를 가져오는 더 나은 방법과 내가 한 방식이 신뢰할 수 있는지 여부에 대해 누군가 의견을 말해줄 수 있습니까?

빠른 버전:

var rootViewController = self.navigationController?.viewControllers.first

목표 C 버전:

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

여기서 self는 UI 탐색 컨트롤러에 내장된 UI View 컨트롤러의 인스턴스입니다.

UI 탐색 컨트롤러의 viewControllers 속성을 사용합니다.코드 예제:

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

이것이 "뒤로" 보기 컨트롤러를 가져오는 표준 방법입니다.이유objectAtIndex:0액세스하려는 뷰 컨트롤러도 루트 컨트롤러이기 때문에 작동합니다. 탐색 깊이가 더 깊으면 백 뷰가 루트 뷰와 동일하지 않을 수 있습니다.

거의 모든 답변에 언급된 동일한 것의 약간 덜 추한 버전:

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;

빠른 확장에 관심이 있는 모든 분들을 위해, 제가 지금 사용하고 있는 것은 다음과 같습니다.

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

@dullgan의 답변에 덧붙여, 그것은 항상 사용하기 좋은 접근법입니다.firstObject위에objectAtIndex:0왜냐하면 첫 번째는 배열에 객체가 없으면 0을 반환하지만, 후자는 예외를 던지기 때문입니다.

UIViewController *rootViewController = self.navigationController.rootViewController;

또는 다음과 같은 범주를 만드는 것이 좋습니다.UINavigationController+Additions거기서 당신의 방법을 참조하십시오.

@interface UINavigationController (Additions)

- (UIViewController *)rootViewController;

@end

@implementation UINavigationController (Additions)

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

@end

저는 이상한 상황에 직면합니다.

self.viewControllers.first항상 루트 뷰 컨트롤러는 아닙니다.

일적으로.self.viewControllers.first는 rootviewController 입니다.하지만 가끔은 그렇지 않습니다.

class MyCustomMainNavigationController: UINavigationController {

    function configureForView(_ v: UIViewController, animated: Bool) {
        let root = self.viewControllers.first
        let isRoot = (v == root)
    
        // Update UI based on isRoot
        // ....
    }
}

extension MyCustomMainNavigationController: UINavigationControllerDelegate {
    func navigationController(_ navigationController: UINavigationController, 
        willShow viewController: UIViewController, 
        animated: Bool) {

        self.configureForView(viewController, animated: animated)
    }
}

내 문제:

일적으로.self.viewControllers.first이라rootviewController.하지만, 내가 전화할 때.popToRootViewController(animated:)그리고 나서 그것은 촉발됩니다.navigationController(_:willShow:animated:) 지금이순간,순간▁at이▁this,지,self.viewControllers.first루트 뷰 컨트롤러가 아니라 사라질 마지막 뷰 컨트롤러입니다.

요약

  • self.viewControllers.first항상 그렇지는 않습니다.rootviewController.때로는 마지막 뷰 컨트롤러가 될 수도 있습니다.

그래서, 나는 계속하는 것을 제안합니다.rootViewControllerself.viewControllers보기 컨트롤러가 하나만 있습니다.에 있습니다.viewDidLoad()사용자 지정 UINavigation 컨트롤러의

class MyCustomMainNavigationController: UINavigationController {
    fileprivate var myRoot: UIViewController!
    override func viewDidLoad() {

        super.viewDidLoad()

        // My UINavigationController is defined in storyboard. 
        // So at this moment, 
        // I can get root viewController by `self.topViewController!`
        let v = self.topViewController!
        self.myRoot = v
    }

}

환경:

  • iOS 14.0.1이 설치된 아이폰 7
  • Xcode 12.0.1(12A7300)

UIA 애플리케이션 싱글톤에 키Windows를 요청하고 UIWindow에서 루트뷰 컨트롤러(rootViewController 속성)를 요청하는 것은 어떻습니까?

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

여기서 저는 어떤 장소에서 뿌리까지 탐색할 수 있는 보편적인 방법을 생각해냈습니다.

  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)
        ...
    }
    

이것은 저에게 효과가 있었습니다.

루트 뷰 컨트롤러가 탐색 컨트롤러에 내장된 경우:

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

하세요.keyWindow사용되지 않습니다.

언급URL : https://stackoverflow.com/questions/1792858/how-do-i-get-the-rootviewcontroller-from-a-pushed-controller