UIPageViewController的setViewController在childViewController中调用意外的视图生命周期

问题描述 投票:1回答:1

[当展示ViewController时,我希望视图的生命周期按顺序排列:

  1. viewDidLoad()
  2. viewWillAppear
  3. viewWillLayoutSubviews()
  4. viewDidLayoutSubviews()
  5. viewDidAppear()

注:在4到5之间可以进行viewWill / viewDidLayoutSubviews()的更多迭代。换句话说,我希望viewDidLayoutSubview在第一个viewDidAppear之前触发。

为了测试这一点,我将一个childViewController添加到UIViewController子类中,并调用addSubview以添加childViewController的视图。

override func viewDidLoad() {
    super.viewDidLoad()

    let childVC = ChildViewController()
    self.addChildViewController(childVC)
    self.view.addSubview(childVC.view)

}

当我打印出视图方法时,这将产生预期的结果:

  1. viewDidLoad()
  2. viewWillAppear
  3. viewWillLayoutSubviews()
  4. viewDidLayoutSubviews()
  5. viewWillLayoutSubviews()
  6. viewDidLayoutSubviews()
  7. viewDidAppear

当我在UIPageViewController子类上使用setViewController时:

override func viewDidLoad() {
    super.viewDidLoad()

    let childVC = ChildViewController()
    self.setViewControllers([childVC], direction: .forward, animated: true, completion: nil)

}

我总是让viewDidAppear在第一个LayoutSubviews方法之前执行:

  1. viewDidLoad()
  2. viewWillAppear
  3. viewDidAppear
  4. viewWillLayoutSubviews()
  5. viewDidLayoutSubviews()
  6. viewWillLayoutSubviews()
  7. viewDidLayoutSubviews()

有人可以解释为什么会发生这种现象吗?

----进一步的观察---

我还为childViewController上的willMove和DidMove方法添加了日志。初始测试的结果:

willMove(toParentViewController:)

  1. viewDidLoad()
  2. viewWillAppear
  3. viewWillLayoutSubviews()
  4. viewDidLayoutSubviews()
  5. viewWillLayoutSubviews()
  6. viewDidLayoutSubviews()
  7. viewDidAppear

UIPageViewController的结果:

  1. viewDidLoad()
  2. viewWillAppear
  3. viewDidAppeardidMove(toParentViewController:)
  4. viewWillLayoutSubviews()
  5. viewDidLayoutSubviews()
  6. viewWillLayoutSubviews()
  7. viewDidLayoutSubviews()

因此看起来setViewController调用了moveToParentViewController,这也许是它较早调用viewDidAppear的原因。

ios swift uipageviewcontroller
1个回答
0
投票
开始和结束看起来像这样:

/* @class UIPageViewController */ -(void)_child:(void *)arg2 beginAppearanceTransition:(bool)arg3 animated:(bool)arg4 { r14 = arg4; r15 = arg3; r12 = [arg2 retain]; if ([self _forwardAppearanceMethods] == 0x0) { objc_unsafeClaimAutoreleasedReturnValue([r12 view]); [r12 beginAppearanceTransition:r15 & 0xff animated:r14 & 0xff]; } [r12 release]; return; }

正如我们在上面看到的,对_forwardAppearanceMethods的调用必须返回0,这会引起问题,并查看其作用:

/* @class UIViewController */
-(bool)_forwardAppearanceMethods {
    r14 = self;
    rax = objc_opt_class(self, _cmd);
    rbx = @selector(shouldAutomaticallyForwardAppearanceMethods);
    rdx = rbx;
    if ([rax doesOverrideViewControllerMethod:rdx] == 0x0) {
            rbx = @selector(automaticallyForwardAppearanceAndRotationMethodsToChildViewControllers);
    }
    rax = *_objc_msgSend;
    rax = (rax)(r14, rbx, rdx, *_objc_msgSend);
    return rax;
}

如我们所见,它的调用shouldAutomaticallyForwardAppearanceMethods已实现为低且为UIPageViewController,如下所示:

/* @class UIPageViewController */
-(bool)shouldAutomaticallyForwardAppearanceMethods {
    return 0x0;
}

注意它也有:

/* @class UIPageViewController */
-(bool)shouldAutomaticallyForwardRotationMethods {
    return 0x0;
}

使用Hopper完成反编译

© www.soinside.com 2019 - 2024. All rights reserved.