iOS 10下UIPopoverPresentationController为空的适配及版本差异咨询
解决iOS 10/11 iPad Popover配置时机差异问题
嘿,这个坑我之前踩过!iOS 10和11在popover的popoverPresentationController初始化时机上确实有明显差异,咱们一步步捋清楚:
一、正确的配置时机(兼容两个版本)
绝对不要在ViewDidLoad里配置!iOS 10里这个属性在ViewDidLoad阶段还没被初始化,自然是空的。推荐这几种可靠的方式:
1. 代码present控制器时,先配置再present
如果你是用代码手动弹出popover,一定要在调用present(_:animated:completion:)之前就配置好popoverPresentationController——只要你把控制器的modalPresentationStyle设为.popover,这个属性就会立刻被创建,不管iOS 10还是11都能正常访问:
let popoverContentVC = YourPopoverViewController() // 先设置弹窗样式为popover popoverContentVC.modalPresentationStyle = .popover // 此时就能拿到popoverPresentationController并配置 if let popoverPC = popoverContentVC.popoverPresentationController { popoverPC.sourceView = self.triggerButton // 设置触发源视图 popoverPC.sourceRect = self.triggerButton.bounds // 设置触发区域 popoverPC.permittedArrowDirections = .any // 允许箭头方向 popoverPC.delegate = self // 如果需要自定义行为的话 } // 最后再present self.present(popoverContentVC, animated: true, completion: nil)
2. Storyboard Segue跳转时,在prepare(for:sender:)里配置
如果是用Storyboard的segue来触发popover,直接在prepare(for:sender:)方法里配置就行——这个时机在两个系统版本里都能稳定获取到popoverPresentationController:
override func prepare(for segue: UIStoryboardSegue, sender: Any?) { guard segue.identifier == "ShowPopoverSegue" else { return } let popoverVC = segue.destination popoverVC.modalPresentationStyle = .popover if let popoverPC = popoverVC.popoverPresentationController { // 这里sender一般是触发的按钮,直接拿来当源视图 popoverPC.sourceView = sender as? UIView popoverPC.sourceRect = (sender as? UIView)?.bounds ?? .zero popoverPC.permittedArrowDirections = .up } }
3. 非要在内容控制器内部配置?用ViewWillAppear(_:)
如果你的业务逻辑必须在popover的内容控制器里配置,那别用ViewDidLoad,改用ViewWillAppear(_:),但记得加个判断避免重复配置:
override func viewWillAppear(_ animated: Bool) { super.viewWillAppear(animated) guard let popoverPC = self.popoverPresentationController else { return } // 确保只配置一次,避免每次视图出现都重复设置 if popoverPC.sourceView == nil { popoverPC.sourceView = self.presentingViewController?.view popoverPC.sourceRect = CGRect(x: 200, y: 200, width: 0, height: 0) } }
不过这种方式不如前两种灵活,毕竟内容控制器可能不知道外部的触发源信息。
二、iOS 10和11的差异根源
- iOS 10及更早:
popoverPresentationController是在控制器被present的过程中才会被实例化,这个时机晚于ViewDidLoad,所以你在ViewDidLoad里访问它就是nil。 - iOS 11及之后:苹果调整了UIKit的内部逻辑,只要你把控制器的
modalPresentationStyle设为.popover,popoverPresentationController会立即被创建,所以在ViewDidLoad里就能正常访问和配置了。
至于不配置的话popover会显示在左上角,这是系统的默认 fallback 行为——当sourceView和sourceRect都没设置时,UIKit就会把popover锚定在屏幕左上角,这个逻辑在两个版本里是一致的。
内容的提问来源于stack exchange,提问作者DwightK
相关产品推荐
相关产品推荐

