탐색 스택에서 이전 뷰 컨트롤러를 식별하는 방법


78

나는이 별도 가지고 navigationcontrollers, 하나 RootViewControllerA와 함께 다른 RootViewControllerB를

ViewControllerC를 A 또는 B의 탐색 스택 으로 푸시 할 수 있습니다.

질문 : 내가 ViewControllerC에 있을 때 내가 A 또는 B에 속하는 스택에 있는지 어떻게 알 수 있습니까?


7
C를 누를 때 설정 한 C에 previousViewController 속성을 생성하지 않는 이유는 무엇입니까? 아니면 A 또는 B를 누를 때 필요한 정보를 C에게 제공 하시겠습니까?
Terry Wilcox 2011 년

1
@TerryWilcox은 '관계가 매우 요즘 복잡 할 수 COS
뱌체슬라프

답변:


107

UINavigationControllerviewControllers속성을 사용할 수 있습니다 .

@property(nonatomic, copy) NSArray *viewControllers

토론 : 루트 뷰 컨트롤러는 어레이의 인덱스 0, 후면 뷰 컨트롤러는 인덱스 n-2, 최상위 컨트롤러는 인덱스 n-1에 있습니다. 여기서 n은 어레이의 항목 수입니다.

https://developer.apple.com/documentation/uikit/uinavigationcontroller

이를 사용하여 루트 뷰 컨트롤러 (배열 인덱스 0에있는 컨트롤러)가 뷰 컨트롤러 A인지 B인지 테스트 할 수 있습니다.


어떻게 이것을 SWIFT에서 문자열로 얻을 수 있습니까? (나는 swift를 처음 사용합니다)
M_R_K

@cyberboy 단지 쉽게로 :와var viewControllers: [UIViewController]
NerdyTherapist

1
이전보기 컨트롤러에있을 것입니다viewControllers.last
부락

@Burak viewControllers.last에는 현재 뷰 컨트롤러가 있습니다. 이전 뷰 컨트롤러를 얻으려면 사용해야합니다.viewControllers[viewControllers.count-2]
Ganpat

102

다음은 허용되는 답변의 구현입니다.

- (UIViewController *)backViewController
{
    NSInteger numberOfViewControllers = self.navigationController.viewControllers.count;

    if (numberOfViewControllers < 2)
        return nil;
    else
        return [self.navigationController.viewControllers objectAtIndex:numberOfViewControllers - 2];
}

20
나는 이것을 카테고리로 추가하는 것이 좋습니다UIViewController
MaxGabriel 2013 년

28
- (UIViewController *)backViewController
{
    NSInteger myIndex = [self.navigationController.viewControllers indexOfObject:self];

    if ( myIndex != 0 && myIndex != NSNotFound ) {
        return [self.navigationController.viewControllers objectAtIndex:myIndex-1];
    } else {
        return nil;
    }
}

11

허용되는 답변의보다 일반적인 구현 :

- (UIViewController *)backViewController {
    NSArray * stack = self.navigationController.viewControllers;

    for (int i=stack.count-1; i > 0; --i)
        if (stack[i] == self)
            return stack[i-1];

    return nil;
}

이렇게하면 현재 클래스가 탐색 스택에있는 위치에 관계없이 올바른 "백 뷰 컨트롤러"가 반환됩니다.


9

확장 으로 tjklemz 코드 의 신속한 구현 :

extension UIViewController {

    func backViewController() -> UIViewController? {        
        if let stack = self.navigationController?.viewControllers {
            for(var i=stack.count-1;i>0;--i) {
                if(stack[i] == self) {
                    return stack[i-1]
                }
            }
        }
        return nil
    }
}

새로운 답변으로 아래의 Swift 3 지원이있는이 코드의 수정 된 버전을 게시했습니다.
Cin316

9

다음 은 Swift 3을 지원하도록 조정하는 Prabhu Beeman의 Swift 코드 수정 된 버전입니다 .

extension UIViewController {
    func backViewController() -> UIViewController? {
        if let stack = self.navigationController?.viewControllers {
            for i in (1..<stack.count).reverse() {
                if(stack[i] == self) {
                    return stack[i-1]
                }
            }
        }
        return nil
    }
}

몇 가지 참고 사항 : reverse ()는 이제 reversed ()이고 self.navigationController? .viewControllers는 "self"뷰 컨트롤러를 포함하지 않으므로 stack.last를 반환하면 충분합니다.
Kappe

3

속성 의 n-2요소에 viewControllers액세스하여 상위 뷰 컨트롤러에 액세스합니다.

해당 인스턴스가 있으면 NSStringFromClass()함수 에서 나오는 항목을 로깅하여 유형을 확인할 수 있습니다 . 또는 static const컨트롤러 A와 B에 식별자 문자열을 보관하고 문자열을 출력하는 getter 함수를 유지할 수 있습니다.


뷰 컨트롤러의 현재 인덱스를 얻는 간단한 방법 또는 계층 구조에 따라 하드 코딩해야합니다.
HpTerm

3

A와 UINavigationController확장 :

extension UINavigationController {

    func previousViewController() -> UIViewController? {
        guard viewControllers.count > 1 else {
            return nil
        }
        return viewControllers[viewControllers.count - 2]
    }

}

2

@tjklemz 코드의 신속한 구현 :

var backViewController : UIViewController? {

        var stack = self.navigationController!.viewControllers as Array

        for (var i = stack.count-1 ; i > 0; --i) {
            if (stack[i] as UIViewController == self) {
                return stack[i-1] as? UIViewController
            }

        }
        return nil
    }

어떻게 이것을 문자열로 얻을 수 있습니까 .. (나는 swift를 처음 사용합니다)
M_R_K

@cyberboy 안녕하세요! 질문을 이해했는지 잘 모르겠습니다. backViewController 설명을 문자열로 가져 오시겠습니까? 그렇다면 다음을 고려할 수 있습니다 println("backViewController is: \(backViewController.description)"). 이렇게하면 "UINavigationController : 0x7fcea1d286b0"과 같은 설명이 제공됩니다. 이는 명확하지 않지만 적어도 개체를 식별 할 수 있도록합니다. 내가 말했듯이 정확히 필요한 것이 무엇인지 잘 모르겠습니다 ...
cdf1982

1

navigationController메소드를 사용하여 검색하십시오. Apple 사이트의 문서를 참조하십시오 .

navigationController 탐색 컨트롤러 인 상위 또는 조상입니다. (읽기 전용)

@property (비 원자, 읽기 전용, 유지) UINavigationController * navigationController

토론 전용은 뷰 컨트롤러가 스택에있는 경우 탐색 컨트롤러를 반환합니다. 탐색 컨트롤러를 찾을 수없는 경우이 속성은 nil입니다.

가용성 아이폰 OS 2.0 이상에서 사용할 수 있습니다.


1

죽은 말은 구타를 즐기기 때문에 :)

- (UIViewController *)previousViewController
{
    NSArray *vcStack = self.navigationController.viewControllers;
    NSInteger selfIdx = [vcStack indexOfObject:self];
    if (vcStack.count < 2 || selfIdx == NSNotFound) { return nil; }
    return (UIViewController *)[vcStack objectAtIndex:selfIdx - 1];
}

1

보다 간결한 신속한 구현 :

extension UIViewController {
    var previousViewController: UIViewController? {
        guard let nav = self.navigationController,
              let myIdx = nav.viewControllers.index(of: self) else {
            return nil
        }
        return myIdx == 0 ? nil : nav.viewControllers[myIdx-1]
    }
}

0

이전 뷰 컨트롤러를 찾는 것은 간단합니다.

귀하의 경우, 즉, C에 있고 B [self.navigationController.viewControllers lastObject]가 필요합니다 .

A는 루트 뷰 컨트롤러 있기 (위해) 때문에 들어, 당신은 대체 할 수 lastObjectfirstObject구하십시오.


0

Swift 2.2 구현- UIViewController확장에 이것을 추가하십시오 . nilviewcontroller가 rootvc이거나 navigationcontroller가 아닌 경우 안전하다는 의미에서 반환 됩니다.

var previousViewController: UIViewController? {
  guard let viewControllers = navigationController?.viewControllers else {
    return nil
  }
  var previous: UIViewController?
  for vc in viewControllers{
    if vc == self {
      break
    }
    previous = vc
  }
  return previous
}

0

가드를 사용하는 Swift와 함께.

extension UIViewController {

    func getPreviousViewController() -> UIViewController? {
        guard let _ = self.navigationController else {
            return nil
        }

        guard let viewControllers = self.navigationController?.viewControllers else {
            return nil
        }

        guard viewControllers.count >= 2 else {
            return nil
        }        
        return viewControllers[viewControllers.count - 2]
    }
}

0

내 확장, 스위프트 3

extension UIViewController {
    var previousViewController: UIViewController? {
        guard let controllers = navigationController?.viewControllers, controllers.count > 1 else { return nil }
        switch controllers.count {
        case 2: return controllers.first
        default: return controllers.dropLast(2).first
        }
    }
}

0

신속한 3의 경우 다음을 수행 할 수 있습니다.

var backtoViewController:UIViewController!
for viewController in (self.navigationController?.viewControllers)!.reversed() {
    if viewController is NameOfMyDestinationViewController {
            backtoViewController = viewController
    }
}
self.navigationController!.popToViewController(backtoViewController, animated: true)

반환하려는 viewController로 "NameOfMyDestinationViewController"를 교체하기 만하면됩니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.