ActionSheet在iPadOS上崩溃但iPhone运行正常的iOS开发问题咨询
问题原因
- 这不是iPadOS的系统bug,是代码写法没有兼容iPad端的弹窗规则:iPhone上
UIActivityViewController默认以底部sheet样式弹出,不需要指定锚点,但iPad上该控件默认以弹出框(popover)样式展示,系统强制要求必须给弹出框设置锚点源(sourceView)或者导航栏按钮项(barButtonItem),否则就会抛出你遇到的异常。 - 之前能运行大概率是旧版iPadOS对该规则的校验比较宽松,新版系统收紧了校验逻辑才会触发崩溃。
修复方案
我们需要在弹出UIActivityViewController之前,针对iPad设备单独配置popover的锚点参数,适配后的代码版本如下:
import SwiftUI struct ContentView: View { // 用来存储触发按钮的UIView引用,作为popover的锚点 @State private var sourceView: UIView? var body: some View { Button(action: actionSheet) { Label("", systemImage: "square.and.arrow.up") } // 拿到SwiftUI View对应的底层UIView .background(UIViewGetter(view: $sourceView)) } func actionSheet() { let av = UIActivityViewController(activityItems: ["Testing"], applicationActivities: nil) // 针对iPad设备配置popover参数 if UIDevice.current.userInterfaceIdiom == .pad { av.popoverPresentationController?.sourceView = sourceView // 设置弹出框指向锚点的位置,这里设为锚点view的bounds,即指向按钮本身 av.popoverPresentationController?.sourceRect = sourceView?.bounds ?? .zero } UIApplication.shared.windows.first?.rootViewController?.present(av, animated: true, completion: nil) } } // 辅助工具:用来获取SwiftUI View对应的底层UIKit UIView struct UIViewGetter: UIViewRepresentable { @Binding var view: UIView? func makeUIView(context: Context) -> UIView { let view = UIView(frame: .zero) view.backgroundColor = .clear DispatchQueue.main.async { // 拿到父view也就是按钮的UIView实例 self.view = view.superview } return view } func updateUIView(_ uiView: UIView, context: Context) {} } struct ContentView_Previews: PreviewProvider { static var previews: some View { ContentView() } }
补充说明
- 如果是把按钮放在导航栏的
ToolbarItem里,也可以直接给popoverPresentationController的barButtonItem属性赋值,不用单独获取sourceView。 - 如果不需要自定义activity项,也可以直接用SwiftUI原生的
ShareLink控件,系统会自动处理多设备适配,不用自己写UIKit桥接代码。
内容的提问来源于stack exchange,提问作者Russ
相关产品推荐
相关产品推荐

