丢失transitioningDelegate的引用,导致在呈现时出现问题

8

在 Xcode beta 2 和 iOS 10 beta 2 之前,我有一个工作正常的自定义UIPresentationController。我没有更改任何代码,但是现在呈现出来的是标准模态呈现。

Apple的UIPresentationController示例代码中有一条注释:

对于将使用自定义呈现控制器的呈现, 它可能也是transitioningDelegate。 这避免了引入另一个对象或 在源视图控制器中实现。

transitioningDelegate不会强制保留其目标对象。 为了防止在调用-presentViewController:animated:completion之前释放presentationController, NS_VALID_UNTIL_END_OF_SCOPE属性附加到声明。

我已经检查了呈现后的视图控制器上的transitioningDelegate。在呈现之前,它是我的自定义UIPresentationController,但呈现后为空。我猜测是引用被释放了,但我找不到Swift中等效的NS_VALID_UNTIL_END_OF_SCOPE。 编辑:我已经验证,在呈现之前设置了transitioningDelegate,但当要进行呈现时就变成了nil。

我在呈现视图控制器中的代码:

@IBAction func buttonAction(_ sender: UIButton) {
    let secondViewController = storyboard!.instantiateViewController(withIdentifier: "NewViewController") as! NewViewController
    let presentationController = MyPresentationController(presentedViewController: secondViewController, presenting: self)
    presentationController.initialFrame = button.frame
    secondViewController.transitioningDelegate = presentationController

    // Move map
    let pixelsToMove: CGFloat = mapView.frame.height / 4
    let region = self.mapView.region

    self.mapView.setRegion(region, offsetBy: pixelsToMove, animated: true)

    // Delegate to NewViewController
    secondViewController.mapView = mapView
    mapView.delegate = secondViewController

    print(secondViewController.transitioningDelegate)
    UIView.animate(withDuration: 0.3, animations: {
        let tabBar = self.tabBarController!.tabBar
        tabBar.frame.origin.y += tabBar.frame.height

        self.present(secondViewController, animated: true, completion: nil)
    })
}

我在UIPresentationController中的代码:

override init(presentedViewController: UIViewController, presenting presentingViewController: UIViewController?) {
    super.init(presentedViewController: presentedViewController, presenting: presentingViewController)
    presentedViewController.modalPresentationStyle = .custom
}

尝试在方法之外先声明presentationController。 - Deepak Kumar
尝试过了,但仍然存在相同的问题。 - jjatie
尝试使用self.presentedViewController.transitioningDelegate。 - Deepak Kumar
就像我说的那样,transitioningDelegate已经被设置了,但就在转换发生之前,引用就丢失了。 - jjatie
2个回答

5
transitioningDelegate属性是一个weak var。可以查看这里的文档。这意味着在设置secondViewController.transitioningDelegate = presentationController时,presentationController的保留计数不会增加。由于你是在方法中实例化presentationController,而且没有其他东西对该对象有强引用,因此它的保留计数将降为0,并在从该函数返回控制权时(在print(secondViewController.transitioningDelegate)之后,因为UIView.animate(...)是异步的),它将变成nil。
在整个视图控制器呈现过程中需要有某种东西来保持对presentationController的强引用。只要有东西强引用它,它的保留计数就不会低于1,直到你明确将该引用设置为nil。一种解决方案是将其保留为当前类或secondViewController的属性。

我今天会尝试这个。为什么在iOS 10 beta 1和9.3.x中它可以工作而不需要创建一个强引用呢? - jjatie
很遗憾,我不确定。我本来也猜想之前这个方法也不会起作用。 - keithbhunter
我尝试使用presenting、presented和presentation控制器的强引用来存储它,但在进行呈现时,transitioningDelegate仍然变为nil。 - jjatie
我投票支持这个答案。在我的呈现视图控制器中,我必须保持 transitioningdelegate 的强引用。当呈现的视图控制器被解除并且 dismissing 转换动画完美播放时,它不会被释放。 - fans3210

2
问题出在beta 2版中,UIViewControllerTransitioningDelegate的方法签名发生了变化,因此它们在我的代码中没有被调用。我不明白为什么,但再次强调,如果不显式存储演示控制器的强引用,一切都可以完美地工作。

那就是我的问题。委托协议具有所有可选函数,因此我的带有不正确签名的函数被静默忽略了。更多信息请参见:https://dev59.com/A5rga4cB1Zd3GeqPrsM-#39513247 - Mathieu Frenette

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接