的开始/结束外观转换的调用不平衡

发布于 2024-12-11 21:45:43 字数 701 浏览 1 评论 0原文

我读到另一位用户遇到类似的错误,但是这个错误是在不同的情况下发生的。

当我最初添加视图控制器时,我收到了这条消息:

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

应用程序的结构如下:

我有一个链接到 5 个视图控制器的 5 个选项卡 TabBarController。在最初的显示选项卡中,我调用了一个新的视图控制器来覆盖作为应用程序的介绍。

我使用此代码调用介绍视图控制器:

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

IntroVC 视图控制器显示后,显示上述错误。

ps 我正在使用 xCode 4.2 & iOS 5.0 SDK,开发iOS 4.3应用程序。

I read SO about another user encountering similar error, but this error is in different case.

I received this message when I added a View Controller initially:

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

The structure of the app is as follow:

I got a 5-tab TabBarController linked to 5 View Controllers. In the initial showing tab, I call out a new View Controller to overlay as an introduction of the app.

I use this code to call the introduction view controller:

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

After this IntroVC view controller shows up, the above error shows.

p.s. I am using xCode 4.2 & iOS 5.0 SDK, developing iOS 4.3 app.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(24

赤濁 2024-12-18 21:45:44

对我来说,发生此错误是因为在设置根视图控制器时,我没有在类的上层声明 UIWindow

            rootViewController?.showTimeoutAlert = showTimeOut
            let navigationController = SwipeNavigationController(rootViewController: rootViewController!)
            self.window = UIWindow(frame: UIScreen.main.bounds)
            self.window?.rootViewController = navigationController
            self.window?.makeKeyAndVisible()

Ex,如果我尝试在该块中声明 window代码而不是引用 self 那么我会收到错误

For me this error occurred because i didn't have UIWindow declared in the upper level of my class when setting a root view controller

            rootViewController?.showTimeoutAlert = showTimeOut
            let navigationController = SwipeNavigationController(rootViewController: rootViewController!)
            self.window = UIWindow(frame: UIScreen.main.bounds)
            self.window?.rootViewController = navigationController
            self.window?.makeKeyAndVisible()

Ex if I tried declaring window in that block of code instead of referencing self then I would receive the error

蓝天白云 2024-12-18 21:45:44

当尝试呈现通过闭包延迟初始化的 UINavigationController 时,将显示此错误。

This error will be displayed when trying to present an UINavigationController that is lazily initialized via a closure.

少跟Wǒ拽 2024-12-18 21:45:44

当我从根 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];

I had this problem when I had navigated from root TVC to TVC A then to TVC B. After tapping the "load" button in TVC B I wanted to jump straight back to the root TVC (no need to revisit TVC A so why do it). I had:

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

...which gave the error "Unbalanced calls to begin/end etc". The following fixed the error, but no animation:

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

This was my final solution, no error and still animated:

//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];
锦欢 2024-12-18 21:45:44

当我将 UIButton 连接到故事板 segue 操作(在 IB 中)时遇到此错误,但后来决定让按钮以编程方式调用 performSegueWithIdentifier 忘记从 IB 中删除第一个。

本质上,它执行了两次 segue 调用,给出了这个错误,并且实际上将我的视图推送了两次。修复方法是删除其中一个 segue 调用。

希望这可以帮助像我一样疲惫的人!

I encountered this error when I hooked a UIButton to a storyboard segue action (in IB) but later decided to have the button programatically call performSegueWithIdentifier forgetting to remove the first one from IB.

In essence it performed the segue call twice, gave this error and actually pushed my view twice. The fix was to remove one of the segue calls.

Hope this helps someone as tired as me!

不寐倦长更 2024-12-18 21:45:44

斯威夫特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

    }

Swift 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

    }
幼儿园老大 2024-12-18 21:45:43

如果没有看到更多周围的代码,我无法给出明确的答案,但我有两种理论。

  1. 您没有使用 UIViewController指定初始化器initWithNibName:bundle:。尝试使用它而不仅仅是 init

  2. 此外,self 可能是选项卡栏控制器的视图控制器之一。始终从最顶层的视图控制器呈现视图控制器,这意味着在这种情况下要求选项卡栏控制器代表视图控制器呈现覆盖视图控制器。您仍然可以将任何回调委托保留给真正的视图控制器,但您必须让选项卡栏控制器存在并关闭。

Without seeing more of the surrounding code I can't give a definite answer, but I have two theories.

  1. You're not using UIViewController's designated initializer initWithNibName:bundle:. Try using it instead of just init.

  2. Also, self may be one of the tab bar controller's view controllers. Always present view controllers from the topmost view controller, which means in this case ask the tab bar controller to present the overlay view controller on behalf of the view controller. You can still keep any callback delegates to the real view controller, but you must have the tab bar controller present and dismiss.

美男兮 2024-12-18 21:45:43

我通过将动画从“是”更改为“否”来修复此错误。

从:

[tabBarController presentModalViewController:viewController animated:YES];

到:

[tabBarController presentModalViewController:viewController animated:NO];

I fixed this error by changing animated from YES to NO.

From:

[tabBarController presentModalViewController:viewController animated:YES];

To:

[tabBarController presentModalViewController:viewController animated:NO];
漫雪独思 2024-12-18 21:45:43

正如 danh 所发布的

您可以通过在应用程序初始化之前显示模态 vc 来生成此警告。即启动一个选项卡式应用程序模板应用程序并在 self.tabBarController 之上呈现一个模态 vc 作为 application:didFinishLaunching 中的最后一行。出现警告。解决方案:首先让堆栈展开,在另一个方法中呈现模态 vc,使用 PerformSelector withDelay:0.0 调用

尝试将该方法移动到 viewWillAppear 中并保护它,以便它只执行一次(建议设置财产)

As posted by danh

You can generate this warning by presenting the modal vc before the app is done initializing. i.e. Start a tabbed application template app and present a modal vc on top of self.tabBarController as the last line in application:didFinishLaunching. Warning appears. Solution: let the stack unwind first, present the modal vc in another method, invoked with a performSelector withDelay:0.0

Try to move the method into the viewWillAppear and guard it so it does get executed just once (would recommend setting up a property)

玩心态 2024-12-18 21:45:43

许多情况下的另一个解决方案是确保 UIViewController 之间的转换发生在不适合的(例如在初始化期间)过程完成之后,通过执行

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

以下 操作:还有pushViewController:animated:等。

Another solution for many cases is to make sure that the transition between UIViewControllers happens after the not-suitable (like during initialization) procedure finishes, by doing:

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

This is general for also pushViewController:animated:, etc.

送舟行 2024-12-18 21:45:43

我也有同样的问题。我在第一个 UIViewController 内的 viewDidLoad 中调用了一个方法。

- (void)viewDidLoad{
    [super viewDidLoad];

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

- (void)loadingView{

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

在第二个 UIViewController 内,我也做了同样的事情,延迟了 0.5 秒。将延迟更改为更高的值后,效果很好。就像在另一个segue之后segue不能执行得太快一样。

I had the same problem. I called a method inside viewDidLoad inside my first UIViewController

- (void)viewDidLoad{
    [super viewDidLoad];

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

- (void)loadingView{

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

Inside the second UIViewController I did the same also with 0.5 seconds delay. After changing the delay to a higher value, it worked fine. It's like the segue can't be performed too fast after another segue.

往事随风而去 2024-12-18 21:45:43

当我需要从另一个视图控制器呈现我的登录视图控制器时,我遇到了同样的问题如果用户未经授权,我在另一个视图控制器的 ViewDidLoad 方法中完成了它(如果未经授权 - >presentModalViewController)。当我开始在 ViewDidAppear 方法中制作它时,我解决了这个问题。我认为 ViewDidLoad 仅初始化属性,然后实际显示视图算法开始!这就是为什么你必须使用 viewDidAppear 方法来进行模式转换!

I had the same problem when I need to Present My Login View Controller from another View Controller If the the User is't authorized, I did it in ViewDidLoad Method of my Another View Controller ( if not authorized -> presentModalViewController ). When I start to make it in ViewDidAppear method, I solved this problem. I Think that ViewDidLoad only initialize properties and after that the actual showing view algorithm begins! Thats why you must use viewDidAppear method to make modal transitions!

玩物 2024-12-18 21:45:43

如果您使用的是 transitioningDelegate(不是本问题示例中的情况),请将 modalPresentationStyle 设置为 .Custom< /代码>

斯威夫特

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

If you're using transitioningDelegate (not the case in this question's example), also set modalPresentationStyle to .Custom.

Swift

let vc = storyboard.instantiateViewControllerWithIdentifier("...")
vc.transitioningDelegate = self
vc.modalPresentationStyle = .Custom
你是年少的欢喜 2024-12-18 21:45:43

我因为拼写错误而遇到这个问题:

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

而不是

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

在超级中调用“WillAppear”而不是“DidAppear”

I had this problem because of a typo:

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

instead of

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

It was calling "WillAppear" in the super instead of "DidAppear"

作死小能手 2024-12-18 21:45:43

我遇到了很多同样的问题。我

  1. 通过使用storyboad instantiateViewControllerWithIdentifier 方法启动ViewController 解决了这个问题。 ie Intro *vc = [self.storyboard instantiateViewControllerWithIdentifier:@"introVC"];
  2. [self.tabBarControllerpresentModalViewController : vcanimated:YES];

我的故事板中有视图控制器,出于某种原因,仅使用 [[introvc alloc] init]; 对我不起作用。

I had lot of problem with the same issue. I solved this one by

  1. Initiating the ViewController using the storyboad instantiateViewControllerWithIdentifier method. i.e Intro *vc = [self.storyboard instantiateViewControllerWithIdentifier:@"introVC"];
  2. [self.tabBarController presentModalViewController : vc animated:YES];

I have the viewcontroller in my storyboard, for some reason using only [[introvc alloc] init]; did not work for me.

最偏执的依靠 2024-12-18 21:45:43

我通过写解决了

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

I solved it by writing

[self.navigationController presentViewController:viewController 
                                        animated:TRUE 
                                      completion:NULL];
慕巷 2024-12-18 21:45:43

我在使用第三方代码时遇到了这个问题。有人忘记在自定义 TabBarController 类中设置 viewWillAppear 和 viewWillDisappear 的 super 内部。

- (void) viewWillAppear:(BOOL)animated {

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

or

- (void) viewWillDisappear:(BOOL)animated {

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

I had this problem with a third party code. Someone forgot to set the super inside of viewWillAppear and viewWillDisappear in a custom TabBarController class.

- (void) viewWillAppear:(BOOL)animated {

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

or

- (void) viewWillDisappear:(BOOL)animated {

    [super viewWillDisappear:animated];
    // code...
}
幸福还没到 2024-12-18 21:45:43

我有同样的错误。我有一个包含 3 个项目的选项卡栏,并且我无意识地尝试使用 performSegueWithIdentifier 调用选项卡栏项目 2 中项目 1 的根视图控制器。

发生的情况是,它调用视图控制器,并在几秒钟后返回到项目 2 的根视图控制器并记录该错误。

显然,您无法将一个项目的根视图控制器调用到另一个项目。

而不是 performSegueWithIdentifier

因此,我使用了 [self.parentViewController.tabBarController setSelectedIndex:0];

希望这对某人有帮助。

I had the same error. I have a tab bar with 3 items and I was unconsciously trying to call the root view controller of item 1 in the item 2 of my tab bar using performSegueWithIdentifier.

What happens is that it calls the view controller and goes back to the root view controller of item 2 after a few seconds and logs that error.

Apparently, you cannot call the root view controller of an item to another item.

So instead of performSegueWithIdentifier

I used [self.parentViewController.tabBarController setSelectedIndex:0];

Hope this helps someone.

不再让梦枯萎 2024-12-18 21:45:43

我遇到了同样的问题,并认为我会发布以防其他人遇到类似的问题。

就我而言,我在 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。

I had the same problem and thought I would post in case someone else runs into something similar.

In my case, I had attached a long press gesture recognizer to my UITableViewController.

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

In my onLongPress selector, I launched my next view controller.

- (IBAction)onLongPress:(id)sender {

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

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

    [page release];

}

In my case, I received the error message because the long press recognizer fired more than one time and as a result, my "SomeViewController" was pushed onto the stack multiple times.

The solution was to add a boolean to indicate when the SomeViewController had been pushed onto the stack. When my UITableViewController's viewWillAppear method was called, I set the boolean back to NO.

静水深流 2024-12-18 21:45:43

我发现,如果您使用故事板,您将需要将呈现新视图控制器的代码放在 viewDidAppear 中。它还将消除“不鼓励在分离视图控制器上呈现视图控制器”警告。

I found that, if you are using a storyboard, you will want to put the code that is presenting the new view controller in viewDidAppear. It will also get rid of the "Presenting view controllers on detached view controllers is discouraged" warning.

Smile简单爱 2024-12-18 21:45:43

Swift 2+ 对我来说有效:

我在故事板中有 UITabBarViewController 并且我有这样的 selectedIndex 属性:

在此处输入图像描述

但我删除了它,并添加到我的 viewDidLoad 方法中我的第一堂课是这样的:

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

我希望我能帮助别人。

In Swift 2+ for me works:

I have UITabBarViewController in storyboard and I had selectedIndex property like this:

enter image description here

But I delete it, and add in my viewDidLoad method of my initial class, like this:

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

I hope I can help someone.

孤独难免 2024-12-18 21:45:43

实际上你需要等到推送动画结束。因此,您可以委托 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];
    }
}

Actually you need to wait till the push animation ends. So you can delegate UINavigationController and prevent pushing till the animation ends.

- (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];
    }
}
羁绊已千年 2024-12-18 21:45:43

正如 @danh 所建议的,我的问题是我在 UITabBarController 准备好之前就呈现了模态 vc。然而,在呈现视图控制器之前,我对依赖固定延迟感到不舒服(根据我的测试,我需要在 performSelector:withDelay: 中使用 0.05-0.1 秒的延迟)。我的解决方案是添加一个在 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

Now in 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;
};

As @danh suggested, my issue was that I was presenting the modal vc before the UITabBarController was ready. However, I felt uncomfortable relying on a fixed delay before presenting the view controller (from my testing, I needed to use a 0.05-0.1s delay in performSelector:withDelay:). My solution is to add a block that gets called on UITabBarController's viewDidAppear: method:

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

Now in 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;
};
怀中猫帐中妖 2024-12-18 21:45:43

您需要确保 -(void)beginAppearanceTransition:(BOOL)isAppearinganimated:(BOOL)animated 和 -(void)endAppearanceTransition 在类中一起创建。

you need make sure -(void)beginAppearanceTransition:(BOOL)isAppearing animated:(BOOL)animated and -(void)endAppearanceTransition is create together in the class.

少女情怀诗 2024-12-18 21:45:43

我有同样的问题。开发时我想绕过屏幕。我通过调用选择器方法在 viewDidLoad 中从一个视图控制器导航到另一个视图控制器。

问题是我们应该让 ViewController 在转换到另一个 ViewController 之前完成转换。

这解决了我的问题:延迟是允许 ViewController 在转换到另一个之前完成转换所必需的。

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

I had the same issue. When developing I wanted to bypass screens. I was navigating from one view controller to another in viewDidLoad by calling a selector method.

The issue is that we should let the ViewController finish transitioning before transitioning to another ViewController.

This solved my problem: The delay is necessary to allow ViewControllers finish transitioning before transitioning to another.

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

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文