내비게이션 컨트롤러에서 한 번에 두 개의 뷰를 팝업하려면 어떻게합니까?


92

탐색 스택의 세 번째보기에서 첫 번째보기로 돌아가고 싶습니다.

한 번에 하나의 뷰를 표시하는 방법을 알고 있습니다.

[self.navigationController popViewControllerAnimated:YES];

그러나 한 번에 두 가지를 어떻게합니까?


2
메타 코멘트 : @lubilis는 최고의 답변입니다. 최고 등급의 답변은 당시에는 좋았지 만 더 이상 관련이 없습니다.
n13

답변:


133

내비게이션 컨트롤러 스택 사이를 이동하는데도 시도 할 수 있습니다.

NSMutableArray *allViewControllers = [NSMutableArray arrayWithArray:[self.navigationController viewControllers]];
for (UIViewController *aViewController in allViewControllers) {
    if ([aViewController isKindOfClass:[RequiredViewController class]]) {
        [self.navigationController popToViewController:aViewController animated:NO];
    }
}

6
IMO이 지금까지 가장 좋은 방법입니다,하지만 당신은 self.navigationcontroller 사용하여 uinavigation 컨트롤러를 참조해야합니다
henghonglee

2
동의합니다. 사용자가 스택을 특정 뷰 컨트롤러로 다시 가져 오려는 경우 이것이 최상의 솔루션입니다. 어떤 viewcontroller인지 모른다고 가정 해 봅시다. 스택에서 꺼내려는 viewcontroller 수를 지정하고 objectAtIndex : (allViewControllers.count-allViewControllers 배열에서 대상 viewcontroller를 가져올 수있는 시스템을 구현할 수 있습니다. 1-금액). -1 왜냐하면 배열은 0부터 시작하기 때문입니다.
Jovan

1
이 솔루션을 좋아하십시오. 정확히 내가 찾던 것
Designer023

3
원래 navigator-> viewControllers 배열을 반복 할 때도 작동합니다 (변경 가능한 배열로 변환 할 필요 없음)
Arik Segal

노트! 이것이 처음부터 끝까지 스택을 반복하므로 정확하게 스택을 뒤집어 야합니다. 같은 종류의 VC가 여러 개있는 경우 스택에서 잘못된 순서로 잘못된 VC를 제거하게됩니다.
StackUnderflow

71

다음은 UINavigationController문제를 해결할 수 있는 두 가지 확장 기능입니다. UIViewController특정 클래스 의 첫 번째 항목을 사용하는 것이 좋습니다 .

extension UINavigationController {

  func popToViewController(ofClass: AnyClass, animated: Bool = true) {
    if let vc = viewControllers.filter({$0.isKind(of: ofClass)}).last {
      popToViewController(vc, animated: animated)
    }
  }

  func popViewControllers(viewsToPop: Int, animated: Bool = true) {
    if viewControllers.count > viewsToPop {
      let vc = viewControllers[viewControllers.count - viewsToPop - 1]
      popToViewController(vc, animated: animated)
    }
  }

}

다음과 같이 사용하십시오.

// pop to SomeViewController class
navigationController?.popToViewController(ofClass: SomeViewController.self)

// pop 2 view controllers
navigationController?.popViewControllers(viewsToPop: 2)

3
Swift (옵션 1)의 경우 둘 removeLastremoveLast(2).
Dominic K

컨트롤러의 라이프 사이클 메소드를 호출하는 것은 어떻습니까? DidAppear 및 요법
마이크 Glukhov

1
(Swift 4)이 줄에 괄호가 누락되었습니다. let vc = viewControllers[viewControllers.count - viewsToPop + 1]올바르게 작동하려면 다음으로 교체해야합니다. let vc = viewControllers[viewControllers.count - (viewsToPop + 1)]또는let vc = viewControllers[viewControllers.count - viewsToPop - 1]
MMiroslav

@MMiroslav 당신이 맞습니다. 내 답변을 업데이트했습니다. Hvala / 주셔서 감사합니다;)
budidino

1
이 답변은 아래에 내 답변을 게시 한 후 업데이트되었습니다. 본질적으로 내 코드의 사본 ^ _ ^
lubilis

44

다음을 사용하여 "루트"(첫 번째) 뷰 컨트롤러로 이동할 수 있습니다 popToRootViewControllerAnimated.

[self.navigationController popToRootViewControllerAnimated:YES];

// If you want to know what view controllers were popd:
// NSArray *popdViewControllers = [self.navigationController popToRootViewControllerAnimated:YES];

UINavigationController참조 :

루트 뷰 컨트롤러를 제외한 스택의 모든 뷰 컨트롤러를 팝하고 디스플레이를 업데이트합니다.

반환 값
스택에서 팝된 뷰 컨트롤러의 배열입니다.


1
하, 내가 그렇게 간단한 대답을 찾기 위해 너무 오래 보냈다는 것을 믿을 수 없다, 감사합니다!
Adam Waite 2011

1
스위프트 3 : self.navigationController? .popToRootViewController (animated : true);
dianakarenms

정확히 내가 찾던 것!
Canucklesandwich

29
[self.navigationController popToViewController:[self.navigationController.viewControllers objectAtIndex:1] animated:YES];   

objectAtIndex : 1-> 원하는 인덱스를 전달할 수 있습니다.


속임수에 감사드립니다, 나는 그것을 잘못된 방법으로하려고했습니다.
Linus

18

스위프트 2-xCode 7.3

이것은 UIViewController를 팝하는 데 매우 유용한 확장이 될 수 있습니다.

extension UINavigationController {

    func popToViewControllerOfType(classForCoder: AnyClass) {
        for controller in viewControllers {
            if controller.classForCoder == classForCoder {
                popToViewController(controller, animated: true)
                break
            }
        }
    }

    func popViewControllers(controllersToPop: Int, animated: Bool) {
        if viewControllers.count > controllersToPop {
            popToViewController(viewControllers[viewControllers.count - (controllersToPop + 1)], animated: animated)
        } else {
            print("Trying to pop \(controllersToPop) view controllers but navigation controller contains only \(viewControllers.count) controllers in stack")
        }
    }
}

2
이것은 더 많은 찬성 투표가 필요합니다 ... 그 확장 프로그램을 작성하려고했습니다. 나는 당신의 감사를 사용하겠습니다;)
n13

1
@ n13 왜 이것이 budidino의 대답보다 낫습니까?
Crashalot

1
확장을 사용하면 코드가 훨씬 더 깔끔해집니다. budidino의 대답을 가져 와서 확장 할 수 있지만 이것은 노력을 절약합니다. 또한이 답변은 오류 사례를 확인하고 오류를 정상적으로 처리합니다 (예 : 보유한 것보다 더 많이 팝하려고 시도)
n13

1
나는이 대답을 좋아한다. 내가 게시 한 답변을 재고하고 업데이트하도록했습니다. viewControllers 배열에서 검색된 클래스의 마지막 인스턴스에 내 코드를 팝하게 만들었습니다. 그게 아마도 원하는 동작이기 때문입니다.
budidino

15

rootViewController가 (방법) '깊이'이기 때문에 한 번에 2를 팝하려는 경우 2를 예로 들면 UIviewController에 범주를 추가하는 것을 고려할 수 있습니다.

UINavigationController + popTwice.h

#import <UIKit/UIKit.h>
@interface UINavigationController (popTwice)

- (void) popTwoViewControllersAnimated:(BOOL)animated;

@end

UINavigationController + popTwice.m

#import "UINavigationController+popTwice.h"

@implementation UINavigationController (popTwice)

- (void) popTwoViewControllersAnimated:(BOOL)animated{
    [self popViewControllerAnimated:NO];
    [self popViewControllerAnimated:animated];
}

@end

#import "UINavigationController+popTwice.h"구현의 어딘가에 범주를 가져 오고 다음 코드 줄을 사용하여 한 번에 두 개의 컨트롤러를 팝합니다.

[self.navigationController popTwoViewControllersAnimated:YES];

대단하지 않습니까? :)


6
세 개의 뷰를 표시해야하는 경우 "UINavigationController + popThrice.m"을 작성합니다. ??????
만나

8
팝업 할 viewController의 수에 대한 매개 변수를 전달하고 [self popViewControllerAnimated : NO]를 래핑 할 수 있습니다. for 루프 내에서 count-1.
noRema

2,3, ... 모든 컨트롤러가 루프로 식별하고 [self.navigationController popToViewControllerAnimated : YES];를 사용하려면 이것은 올바른 방법이 아닙니다. 위에서 언급 한 것은 매우 나쁜 코딩이며 깜박이는 UI와 나쁜 사용자 경험을 보여줄 수 있습니다.
Vicky Dhas

10

스위프트 4 :

func popViewControllerss(popViews: Int, animated: Bool = true) {
    if self.navigationController!.viewControllers.count > popViews
    {
        let vc = self.navigationController!.viewControllers[self.navigationController!.viewControllers.count - popViews - 1]
         self.navigationController?.popToViewController(vc, animated: animated)
    }
}

그런 다음이 방법 사용

self.popViewControllerss(popViews: 2)

좋아, 내가 찾던 것. 고마워.
maddysan

6

이것을 시도해 볼 수도 있습니다 :-

[self.navigationController popToViewController:yourViewController animated:YES];

6
//viewIndex = 1;
//viewIndex = 2;
//viewIndex = 3;

// **[viewControllers objectAtIndex: *put here your viewindex number*]

NSArray *viewControllers = [self.navigationController viewControllers];
[self.navigationController popToViewController:[viewControllers objectAtIndex:viewIndex] animated:NO];

4
    NSMutableArray *newStack = [NSMutableArray arrayWithArray:[self.navigationController viewControllers]];
    [newStack removeLastObject];
    [newStack removeLastObject];
    [self.navigationController setViewControllers:newStack animated:YES];

4

Swift 3에서는 이와 같은 내비게이션 컨트롤러에서 하나, 둘 또는 그 이상의 뷰 컨트롤러를 팝할 수 있습니다.

let viewControllers = self.navigationController!.viewControllers as [UIViewController]
    for aViewController:UIViewController in viewControllers {
        if aViewController.isKind(of: FromWhereYouWantToGoController.self) {
            _ = self.navigationController?.popToViewController(aViewController, animated: true)
        }
    }

여기서 FromWhereYouWantToGoController는 대상 컨트롤러입니다. 도움이 되었기를 바랍니다.


3

초기 뷰 컨트롤러 (돌아 오려는 컨트롤러)를 전달한 다음 마지막 뷰에서 다음 줄을 호출 할 수 있습니다.

[self.navigationController popToViewController:yourInitialViewController animated:YES];

엘.


3

나는 여기 에서이 대답을 보지 못했습니다. 루트까지가 아니라 몇 개만 팝하려는 경우 self.navigationController.viewControllers에서 클래스 유형 확인을 반복하거나 참조가있는 경우 다음을 사용할 수 있습니다.

for (UIViewController *aViewController in self.navigationController.viewControllers) {
   if ([aViewController isKindOfClass:[SMThumbnailViewController class]]) {
      [self.navigationController popToViewController:aViewController animated:YES];
   }
}

2

루트 뷰 컨트롤러로 돌아갈 수 있습니다.

[self.navigationController popToRootViewControllerAnimated:YES];

또는 팝업하려는보기가 첫 번째보기가 아닌 경우 이전보기의 viewWillAppear에서 다시 팝업해야합니다.


2

다음은 X ViewController로 돌아가는 데 사용하는 작은 함수입니다.

-(void)backMultiple:(id)data {
    int back = 2; //Default to go back 2 
    int count = [self.navigationController.viewControllers count];

    if(data[@"count"]) back = [data[@"count"] intValue];

    //If we want to go back more than those that actually exist, just go to the root
    if(back+1 > count) {
        [self.navigationController popToRootViewControllerAnimated:YES];
    }
    //Otherwise go back X ViewControllers 
    else {
        [self.navigationController popToViewController:[self.navigationController.viewControllers objectAtIndex:count-(back+1)] animated:YES];
    }
}

2

(Swift 1.2 / Xcode 6.3.1)의 Swift 버전이 두 번 이상 튀어 나옴

 var viewControllers = self.navigationController?.viewControllers
 viewControllers?.removeLast()
 viewControllers?.removeLast()
 self.navigationController?.setViewControllers(viewControllers, animated: true)

또는

 var viewControllers = self.navigationController?.viewControllers
 var viewsToPop = 2
 var end = (viewControllers?.count)!
 var start = end - viewsToPop
 viewControllers?.removeRange(Range<Int>(start: start, end: end))
 self.navigationController?.setViewControllers(viewControllers, animated: true)

1

UIViewController의 스택을 사용할 수 있습니다. 1. 스택에있는 모든 viewController의 배열을 가져옵니다. 2. 전체 배열을 반복
하고 클래스 유형을 일치시켜 원하는 viewController 를 찾습니다 . 3. viewController를 팝니다.

func popToSpecificViewC
{
let viewControllers: [UIViewController] = self.navigationController!.viewControllers as [UIViewController];
        for viewController:UIViewController in viewControllers
        {
            if viewController.isKind(of: WelcomeViewC.self)
            {
                _ = self.navigationController?.popToViewController(viewController, animated: true)
            }
        }
}

0

간단한 UINavigationController 확장 사용 :

extension UINavigationController {
    func popViewControllers(_ count: Int) {
        guard viewControllers.count > count else { return }
        popToViewController(viewControllers[viewControllers.count - count - 1], animated: true)
    }
}
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.