viewDidAppear:在启动期间呈现的模态视图控制器上调用两次

发布于 2024-07-14 19:51:27 字数 1828 浏览 10 评论 0原文

解决方案:在尝试在新项目中重新创建此错误以提交给 Apple 时,我发现它特定于 iPhone OS 2.1,并且编译 2.2 修复了该问题。 斯蒂芬,谢谢你的帮助; 我会接受你的答案,因为如果 bug 仍然存在或者我不愿意编译 2.2,它就会起作用。


我有一个应用程序正在从根本上改变其数据库模式,要求我在代码中将旧式记录转换为新式记录。 由于用户可能在此应用程序中存储大量数据,因此我尝试在传输数据时显示带有进度条的模式视图控制器(即作为用户看到的第一件事)。 该视图控制器的 viewDidAppear: 开始一个数据库事务,然后启动一个后台线程来执行实际的移植,偶尔会使用performSelectorInMainThread:withObject:waitUntilDone: 告诉前台线程更新进度条。

问题是,viewDidAppear: 被调用了两次。 我注意到这一点是因为“启动事务”步骤失败并显示“数据库繁忙”消息,但设置断点表明它确实被调用了两次 - 一次由 -[UIViewController viewDidMoveToWindow:shouldAppearOrDisappear:] ,并再次通过 -[UIViewController modalPresentTransitionDidComplete]。 这些名称似乎是私有 UIViewController 方法,所以我猜测这要么是一个框架错误,要么我正在做一些 UIKit 不希望我做的事情。

两个相关的代码摘录(一些不相关的代码已被总结):

- (void)applicationDidFinishLaunching:(UIApplication *)application {
    (register some default settings in NSUserDefaults)

    // doing this early because trying to present a modal view controller 
    // before the view controller is visible seems to break it
    [window addSubview:[self.navigationController view]];

    // this is the method that may present the modal view
    [self.databaseController loadDatabaseWithViewController:self.navigationController];

    if(!self.databaseController.willUpgrade) {
        [self restoreNavigationControllerState];
    }
}

来自我的 DatabaseController 类:

- (void)loadDatabaseWithViewController:(UIViewController*)viewController {
    (open the new database)

    (compute the path the old database would live at if it existed)

    if([[NSFileManager defaultManager] fileExistsAtPath:oldDBPath]) {
        (open the old database)

        [viewController presentModalViewController:self animated:NO];
    }
}

那么,我在这里搞砸了什么,还是应该向 Apple 提交错误报告?

Resolution: While trying to recreate this bug in a fresh project to submit to Apple, I discovered that it is specific to iPhone OS 2.1, and compiling for 2.2 fixes the problem. Stephen, thanks for your help; I'll be accepting your answer since it would have worked if the bug still existed or I wasn't willing to compile for 2.2.


I have an app which is radically changing its database schema in a way that requires me to transform old-style records to new-style ones in code. Since users may store a lot of data in this app, I'm trying to display a modal view controller with a progress bar while it ports the data over (i.e. as the very first thing the user sees). This view controller's viewDidAppear: begins a database transaction and then starts a background thread to do the actual porting, which occasionally uses performSelectorInMainThread:withObject:waitUntilDone: to tell the foreground thread to update the progress bar.

The problem is, viewDidAppear: is being called twice. I noticed this because that "start a transaction" step fails with a "database busy" message, but setting a breakpoint reveals that it is indeed called two times—once by -[UIViewController viewDidMoveToWindow:shouldAppearOrDisappear:], and again by -[UIViewController modalPresentTransitionDidComplete]. Those names appear to be private UIViewController methods, so I'm guessing this is either a framework bug, or I'm doing something UIKit isn't expecting me to do.

Two relevant code excerpts (some irrelevant code has been summarized):

- (void)applicationDidFinishLaunching:(UIApplication *)application {
    (register some default settings in NSUserDefaults)

    // doing this early because trying to present a modal view controller 
    // before the view controller is visible seems to break it
    [window addSubview:[self.navigationController view]];

    // this is the method that may present the modal view
    [self.databaseController loadDatabaseWithViewController:self.navigationController];

    if(!self.databaseController.willUpgrade) {
        [self restoreNavigationControllerState];
    }
}

And from my DatabaseController class:

- (void)loadDatabaseWithViewController:(UIViewController*)viewController {
    (open the new database)

    (compute the path the old database would live at if it existed)

    if([[NSFileManager defaultManager] fileExistsAtPath:oldDBPath]) {
        (open the old database)

        [viewController presentModalViewController:self animated:NO];
    }
}

So, is there something I'm screwing up here, or should I file a bug report with Apple?

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

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

发布评论

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

评论(1

栖竹 2024-07-21 19:51:27

我也在我的应用程序中看到了这个。 我从未完全确认过这一点,但我认为这就是发生的情况:

  1. 加载根视图
  2. 加载模态视图
  3. 操作系统发送视图 在步骤 1 中确实出现了视图的通知
  4. 当前 视图控制器,在本例中发生了作为您的 DatabaseController 类,选择它
  5. 操作系统发送视图确实出现模式视图的通知
  6. 当前视图控制器获取通知。 在本例中,它与上次的控制器完全相同。

在我的例子中,我只是重置了第一次调用 viewDidAppear: 时发生的情况。

在您的情况下,我会想到两个选项:一个静态变量来跟踪您是否已经开始升级; 或者查看启动前传入的UIView*参数。

I saw this in my app too. I never got it entirely confirmed, but I think this is what's happening:

  1. Load root view
  2. Load modal view
  3. OS sends view did appear notification for the view in step 1
  4. The current view controller, which in this instance happens to be your DatabaseController class, picks it up
  5. OS sends the view did appear notification for the modal view
  6. The current view controller gets the notification. In this case it's the exact same controller as last time

In my case I just reset what happened in the first call to viewDidAppear:.

In your case two options spring to mind: a static variable to track whether you've started the upgrade already; or look at the UIView* parameter passed in before starting.

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