<UITabBarController : 0x197870>의 시작 / 종료 모양 전환을위한 불균형 호출


119

비슷한 오류 가 발생하는 다른 사용자에 대해 읽었 지만이 오류는 다른 경우입니다.

처음에 View Controller를 추가했을 때이 메시지를 받았습니다.

Unbalanced calls to begin/end appearance transitions for 
<UITabBarController: 0x197870>

앱의 구조는 다음과 같습니다.

5 개의 뷰 컨트롤러에 연결된 5 개의 탭 TabBarController가 있습니다. 초기 표시 탭에서 앱 소개로 오버레이 할 새 View Controller를 호출합니다.

이 코드를 사용하여 소개보기 컨트롤러를 호출합니다.

IntroVC *vc = [[IntroVC alloc] init];
[self presentModalViewController:vc animated:YES];
[vc release]; 

IntroVC뷰 컨트롤러가 나타나면 위의 오류가 표시됩니다.

추신 저는 xCode 4.2 및 iOS 5.0 SDK를 사용하여 iOS 4.3 앱을 개발하고 있습니다.


안녕하세요 Shivan, 당신과 같은 문제가 있습니다. 그러나 아래 답변을 본 후에도 여전히 수정할 수 없습니다. 소개 뷰 컨트롤러를 어디에서 부르는지 알 수 있습니까?
ZYiOS

답변:


98

주변 코드를 더 많이 보지 않으면 확실한 답을 줄 수는 없지만 두 가지 이론이 있습니다.

  1. UIViewController지정된 이니셜 라이저를initWithNibName:bundle: 사용하고 있지 않습니다 . 대신 사용하십시오 init.

  2. 또한 self탭 막대 컨트롤러의보기 컨트롤러 중 하나 일 수 있습니다. 항상 최상위 뷰 컨트롤러에서 뷰 컨트롤러를 표시합니다. 즉,이 경우 탭 막대 컨트롤러에 뷰 컨트롤러 대신 오버레이 뷰 컨트롤러를 표시하도록 요청합니다. 실제 뷰 컨트롤러에 대한 콜백 델리게이트를 계속 유지할 수 있지만 탭 막대 컨트롤러가 있고 닫혀 있어야합니다.


2
# 1은 나를 위해이 문제를 해결했으며 init 대신 initWithNibName : nil bundle : nil을 사용했습니다.
Hua-Ying

172
앱 초기화가 완료되기 전에 모달 vc를 표시하여이 경고를 생성 할 수 있습니다. 즉, 탭이있는 애플리케이션 템플릿 앱을 시작하고 application : didFinishLaunching의 마지막 줄로 self.tabBarController 위에 모달 vc를 표시합니다. 경고가 나타납니다. 솔루션 : 스택을 먼저 풀고, performSelector withDelay : 0.0으로 호출 된 다른 메서드에서 모달 vc를 표시합니다.
danh

9
그리고 여기에 performSelector withDelay가 작동하는 이유를 설명하는 또 다른 질문이 있습니다. stackoverflow.com/questions/1922517/…
fatih

1
danh의 솔루션은 나를 위해 일했지만 0.0이 아닌 0.1을 사용해야했습니다.
Brandon O'Rourke

11
0의 performSelectorWithDelay를 사용하는 대신 viewDidLoad 등이 아닌 viewDidAppear에서이를 수행하십시오.
tooluser 2014 년

40

애니메이션을 YES에서 NO로 변경하여이 오류를 수정했습니다.

에서:

[tabBarController presentModalViewController:viewController animated:YES];

에:

[tabBarController presentModalViewController:viewController animated:NO];

4
애니메이션에 관심이없는 경우 문제가 해결되지만 애니메이션이 필요한 경우 : 예, 허용 된 답변에 대한 danh의 의견을 시도해보십시오. stackoverflow.com/questions/7886096/…
wxactly

3
참고 : presentModalViewController : animated : iOS6에서 더 이상 사용되지 않습니다.
ZS

16

danh 에 의해 게시

앱 초기화가 완료되기 전에 모달 vc를 표시하여이 경고를 생성 할 수 있습니다. 즉, 탭이있는 애플리케이션 템플릿 앱을 시작하고 application : didFinishLaunching의 마지막 줄로 self.tabBarController 위에 모달 vc를 표시합니다. 경고가 나타납니다. 솔루션 : 스택을 먼저 풀고, performSelector withDelay : 0.0으로 호출 된 다른 메서드에서 모달 vc를 제공합니다.

메서드를 viewWillAppear로 이동하고 한 번만 실행되도록 보호합니다 (속성 설정을 권장합니다).


viewWillAppear안돼 viewDidAppear?
CyberMew

6

많은 경우에 대한 또 다른 해결책은 다음을 수행하여 적합하지 않은 (예 : 초기화 중) 프로 시저가 완료된 UIViewController s 간의 전환이 발생 하는지 확인하는 것입니다.

__weak MyViewController *weakSelf = self;
dispatch_async(dispatch_get_main_queue(), ^{
    [weakSelf presentViewController:vc animated:YES];
});

이것은 또한 일반적입니다 pushViewController:animated:.


4

나는 같은 문제가 있었다. viewDidLoad내 첫 번째 내부 메서드를 호출UIViewController

- (void)viewDidLoad{
    [super viewDidLoad];

    [self performSelector:@selector(loadingView)
               withObject:nil afterDelay:0.5];
}

- (void)loadingView{

    [self performSegueWithIdentifier:@"loadedData" sender:self];
}

제 2 내측 UIViewController나는 0.5 초 지연과 같은했다. 지연을 더 높은 값으로 변경 한 후 제대로 작동했습니다. 그것은 segue가 다른 segue 후에 너무 빨리 수행 될 수없는 것과 같습니다.


7
뷰 라이프 사이클 메소드 인 viewDidAppear는 정확히이 목적을 위해 제공되며 인위적인 지연 fwiw를 도입하는 것보다 더 신뢰할 수 있습니다.
tooluser 2014 년

1
0의 지연이 내비게이션 컨트롤러가 새 내비게이션을 준비 할 때까지 기다릴 수 있다는 점을 제외하면 정답입니다.
malhal

그것은 완전히 맞습니다, 당신은 그것을 처리 할 준비가 viewDidAppear되도록 그것을 안으로 불러야 UINavigationController합니다. 내 게시물을 이것으로 변경했습니다.)
Alex Cio 2014 년

나는 이것이 viewWillAppear로 옮겨 져야한다고 느낀다. 그러면 뷰가 초기화되었는지 여부에 대해 걱정할 필요가 없다.
horsejockey

3

다른 뷰 컨트롤러에서 로그인 뷰 컨트롤러를 제시해야 할 때도 같은 문제가 발생했습니다. 사용자가 승인되지 않은 경우 다른 뷰 컨트롤러의 ViewDidLoad 메서드에서 수행했습니다 (권한이없는 경우-> presentModalViewController). ViewDidAppear 메서드에서 만들기 시작했을 때이 문제를 해결했습니다. ViewDidLoad는 속성 만 초기화하고 그 후에 실제보기 알고리즘이 시작된다고 생각합니다! 이것이 모달 전환을 위해 viewDidAppear 메서드를 사용해야하는 이유입니다!


3

오타 때문에이 문제가 발생했습니다.

override func viewDidAppear(animated: Bool) {
    super.viewWillAppear(animated)

대신에

override func viewDidAppear(animated: Bool) {
    super.viewDidAppear(animated)

수퍼에서 "DidAppear"대신 "WillAppear"를 호출했습니다.


2

나는 같은 문제에 많은 문제가 있었다. 나는 이것을 하나 해결했다

  1. storyboad instantiateViewControllerWithIdentifier 메서드를 사용하여 ViewController를 시작합니다. 즉Intro *vc = [self.storyboard instantiateViewControllerWithIdentifier:@"introVC"];
  2. [self.tabBarController presentModalViewController : vc animated:YES];

내 스토리 보드에 뷰 컨트롤러가 있습니다. 어떤 이유로 든 [[introvc alloc] init];저 에게만 작동하지 않았습니다.


1
새로운 스토리 보드 기능을 사용하게되어 반갑습니다. 하지만 제 경우에는 스토리 보드를 사용하지 않았습니다 ...
Raptor 2011

"instantiateViewControllerWithIdentifier"가 컨트롤러의 식별자를 취한다는 점을 지적하고 싶었습니다. 자세한 내용은 체크 아웃 stackoverflow.com/questions/8186375/...
Kishor Kundan

2

나는 글로 그것을 해결했다

[self.navigationController presentViewController:viewController 
                                        animated:TRUE 
                                      completion:NULL];

3
좀 더 관용적이며 더 안전
해지려면

2
좀 더 관용적이지만 어떻게 더 안전한가요?
Zev Eisenberg

2

타사 코드에이 문제가 발생했습니다. 누군가가 사용자 정의 TabBarController 클래스에서 viewWillAppear 및 viewWillDisappear 내부에 수퍼를 설정하는 것을 잊었습니다.

- (void) viewWillAppear:(BOOL)animated {

    [super viewWillAppear:animated];
    // code...
}

or

- (void) viewWillDisappear:(BOOL)animated {

    [super viewWillDisappear:animated];
    // code...
}

2

사용 transitioningDelegate하는 경우 (이 질문의 예에서는 해당되지 않음)로 설정 modalPresentationStyle하십시오 .Custom.

빠른

let vc = storyboard.instantiateViewControllerWithIdentifier("...")
vc.transitioningDelegate = self
vc.modalPresentationStyle = .Custom

1

나는 같은 오류가 있었다. 3 개의 항목이있는 탭 표시 줄이 있는데 무의식적으로을 사용하여 탭 표시 줄의 항목 2에서 항목 1의 루트 뷰 컨트롤러를 호출하려고했습니다 performSegueWithIdentifier.

무슨 일이 일어나는지보기 컨트롤러를 호출하고 몇 초 후에 항목 2의 루트보기 컨트롤러로 돌아가서 해당 오류를 기록합니다.

분명히 항목의 루트 뷰 컨트롤러를 다른 항목으로 호출 할 수 없습니다.

그래서 대신 performSegueWithIdentifier

나는 사용했다 [self.parentViewController.tabBarController setSelectedIndex:0];

이것이 누군가를 돕기를 바랍니다.


1

나는 똑같은 문제가 있었고 다른 누군가가 비슷한 것을 겪을 경우 게시 할 것이라고 생각했습니다.

제 경우에는 UITableViewController에 길게 누르기 제스처 인식기를 연결했습니다.

UILongPressGestureRecognizer *longPressGesture = [[[UILongPressGestureRecognizer alloc]
                                                   initWithTarget:self
                                                   action:@selector(onLongPress:)]
                                                  autorelease];
[longPressGesture setMinimumPressDuration:1];
[self.tableView addGestureRecognizer:longPressGesture];

onLongPress 선택기에서 다음보기 컨트롤러를 시작했습니다.

- (IBAction)onLongPress:(id)sender {

    SomeViewController* page = [[SomeViewController alloc] initWithNibName:@"SomeViewController" bundle:nil];

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

    [page release];

}

제 경우에는 길게 누름 인식기가 한 번 이상 실행되어 "SomeViewController"가 여러 번 스택에 푸시 되었기 때문에 오류 메시지를 받았습니다.

해결책은 SomeViewController가 스택에 푸시 된시기를 나타내는 부울을 추가하는 것이 었습니다. 내 UITableViewController의 viewWillAppear 메서드가 호출되었을 때 부울을 다시 NO로 설정했습니다.


1

스토리 보드를 사용하는 경우 viewDidAppear에 새 뷰 컨트롤러를 표시하는 코드를 넣는 것이 좋습니다. 또한 "분리 된 뷰 컨트롤러에 뷰 컨트롤러를 표시하는 것은 권장되지 않습니다."라는 경고도 제거됩니다.


1

에서 2 + 스위프트 나 작동을 위해 :

스토리 보드에 UITabBarViewController가 있고 다음과 같이 selectedIndex 속성이 있습니다.

여기에 이미지 설명 입력

그러나 나는 그것을 삭제하고 다음과 같이 초기 클래스의 viewDidLoad 메소드를 추가합니다.

override func viewDidLoad() {
   super.viewDidLoad()
   self.tabBarController?.selectedIndex = 2
}

누군가를 도울 수 있기를 바랍니다.


0

실제로 푸시 애니메이션이 끝날 때까지 기다려야합니다. 따라서 UINavigationController를 위임하고 애니메이션이 끝날 때까지 밀지 않도록 할 수 있습니다.

- (void)navigationController:(UINavigationController *)navigationController didShowViewController:(UIViewController *)viewController animated:(BOOL)animated{
    waitNavigation = NO;
}


-(void)showGScreen:(id)gvc{

    if (!waitNavigation) {
        waitNavigation = YES;
        [_nav popToRootViewControllerAnimated:NO];
        [_nav pushViewController:gvc animated:YES];
    }
}

셀이 선택되면 호출합니다. 사실은 당신에게 달려있다
ymutlu

0

@danh가 제안했듯이 내 문제 UITabBarController는 준비 되기 전에 모달 vc를 제공한다는 것 입니다. 그러나 뷰 컨트롤러를 표시하기 전에 고정 지연에 의존하는 것이 불편 함을 느꼈습니다 (테스트에서에서 0.05-0.1s 지연을 사용해야했습니다 performSelector:withDelay:). 내 솔루션은 UITabBarControllerviewDidAppear:메서드 에서 호출되는 블록을 추가하는 것입니다.

PRTabBarController.h :

@interface PRTabBarController : UITabBarController

@property (nonatomic, copy) void (^viewDidAppearBlock)(BOOL animated);

@end

PRTabBarController.m :

#import "PRTabBarController.h"

@implementation PRTabBarController

- (void)viewDidAppear:(BOOL)animated {
    [super viewDidAppear:animated];
    if (self.viewDidAppearBlock) {
        self.viewDidAppearBlock(animated);
    }
}

@end

지금에 application:didFinishLaunchingWithOptions:

PRTabBarController *tabBarController = [[PRTabBarController alloc] init];

// UIWindow initialization, etc.

__weak typeof(tabBarController) weakTabBarController = tabBarController;
tabBarController.viewDidAppearBlock = ^(BOOL animated) {
    MyViewController *viewController = [MyViewController new];
    viewController.modalPresentationStyle = UIModalPresentationOverFullScreen;
    UINavigationController *navigationController = [[UINavigationController alloc] initWithRootViewController:viewController];
    [weakTabBarController.tabBarController presentViewController:navigationController animated:NO completion:nil];
    weakTabBarController.viewDidAppearBlock = nil;
};

0

-(void) beginAppearanceTransition : (BOOL) isAppearing animated : (BOOL) animated 및-(void) endAppearanceTransition이 클래스에서 함께 생성되는지 확인해야합니다.


0

나는 같은 문제가 있었다. 개발할 때 화면을 우회하고 싶었습니다. 선택기 메서드를 호출하여 viewDidLoad에서 한 뷰 컨트롤러에서 다른 뷰 컨트롤러로 이동했습니다.

문제는 다른 ViewController로 전환하기 전에 ViewController가 전환을 완료하도록해야한다는 것입니다.

이것은 내 문제를 해결했습니다. ViewController가 다른 것으로 전환하기 전에 전환을 완료하려면 지연이 필요합니다.

self.perform(#selector(YOUR SELECTOR METHOD), with: self, afterDelay: 0.5)

0

스위프트 5

 func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) {


//Delete or comment the below lines on your SceneDelegate.

//        guard let windowScene = (scene as? UIWindowScene) else { return }
//        window?.windowScene = windowScene
//        window?.makeKeyAndVisible()

        let viewController = ListVC()
        let navViewController = UINavigationController(rootViewController: viewController)
        window?.rootViewController = navViewController

    }

-1

루트 TVC에서 TVC A로 이동 한 다음 TVC B로 이동했을 때이 문제가 발생했습니다. TVC BI에서 "로드"버튼을 탭한 후 바로 루트 TVC로 바로 돌아가고 싶었습니다 (TVC A를 다시 방문 할 필요가없는 이유가 무엇입니까). . 나는 :

//Pop child from the nav controller
[self.navigationController popViewControllerAnimated:YES];
//Pop self to return to root
[self.navigationController popViewControllerAnimated:YES];

... "시작 / 종료 등 불균형 호출"오류가 발생했습니다. 다음은 오류를 수정했지만 애니메이션은 없습니다.

//Pop child from the nav controller
[self.navigationController popViewControllerAnimated:NO];
//Then pop self to return to root
[self.navigationController popViewControllerAnimated:NO];

이것은 내 최종 솔루션이었고 오류가 없었으며 여전히 애니메이션되었습니다.

//Pop child from the nav controller
[self.navigationController popViewControllerAnimated:NO];
//Then pop self to return to root, only works if first pop above is *not* animated
[self.navigationController popViewControllerAnimated:YES];

-1

UIButton을 스토리 보드 segue 액션 (IB에서)에 연결했을 때이 오류가 발생했지만 나중에 버튼이 프로그래밍 방식으로 호출하도록 결정했습니다. performSegueWithIdentifier 에서 첫 번째 항목을 제거하는 것을 잊어 버리는 것을 .

본질적으로 그것은 segue 호출을 두 번 수행 하고이 오류를 주었고 실제로 내 견해를 두 번 밀었습니다. 수정 사항은 segue 호출 중 하나를 제거하는 것입니다.

이것이 나만큼 피곤한 사람에게 도움이되기를 바랍니다!

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