UIActionController 的 .actionSheet 样式,在 iPhone 和 iPad 上会有不同的呈现方式。在 iPad 和 Mac 上不会以强制回应(Modal)对话视窗的方式呈现提示控制器(alert controller),而是使用弹出(popover)的样式。

这个呈现的过程是由 iOS 或 Mac OS 自动处理,当呼叫以下这行程序时,iOS 或 Mac OS 将会检查装置是 iPhone 还是 iPad。

present(optionMenu, animated: true, completion: nil)

如果装置是 iPhone 的话,提示控制器会以强制回应对话视窗来呈现,而在 iPad 和 Mac,提示控制器则会使用储存在 popoverPresentationController 属性中的 UIPopoverPresentationController 物件。

在使用弹出样式来呈现提示视图控制器时,你必须配置 popoverPresentationController 的来源视图,这个来源视图标示了所弹出的矩形视图。如果没有配置的话,在 iPad 运行时会报错闪退(或者卡死)。在把程序设置为可以在 macOS 10.15 上运行,并对 mac 系统进行构建,会发现出现和 iPad 上一样的 bug,会出现卡死。

You must provide location information for this popover through the alert controller’s popoverPresentationController. You must provide either a sourceView and sourceRect or a barButtonItem.

在 iPad 上运行时,会报错如上

现在在 tableView(_:didSelectRowAt:) 的方法中插入以下的程序,将程序放在 optionMenu 的实例之后。

if let popoverController = optionMenu.popoverPresentationController {
    if let cell = tableView.cellForRow(at: indexPath) {
        popoverController.sourceView = cell
        popoverController.sourceRect = cell.bounds
    }
}

当 App 在 iPhone 执行时,提示控制器(也就是 optionMenu)的 popoverPresentationController 属性是设为 nil,反之,在 iPad 执行时,则会存放弹出显示视图控制器(popover presentation controller),因此,我们使用 if let 来检查 popoverPresentationController 属性是否有一个值。如果是的话,我们配置 sourceView 为 Cell,并使用 Cell 来触发动作。另外,我们设定 sourceRect 属性为 Cell 的边界,因此,窗口弹出的原点是来自 Cell 的中心。

这时,这个应用在 iPad 和 macos 上才能无障碍运行。UIActivityViewController 在较大的装置(iPad 和 Mac)会以弹出样式来呈现。这点在开发跨平台应用时应该格外注意。