SpriteKit游戏在iPad上使用Popover展示ActivityViewController时崩溃
我之前在SpriteKit项目里踩过一模一样的iPad适配坑!那种明明照着教程配置,iPhone跑起来好好的,iPad一到分享就崩溃还没半点报错信息的感觉,真的让人头大。结合我当时的解决经验,给你几个排查方向:
先搞定视图层级:从正确的UIViewController弹出Popover
SpriteKit的SKScene本身不是UIViewController,直接在场景里调用present方法肯定会出问题。你得先拿到当前SKView所属的UIViewController。可以给UIView加个扩展来快速获取:extension UIView { func parentViewController() -> UIViewController? { var parentResponder: UIResponder? = self while parentResponder != nil { parentResponder = parentResponder!.next if let viewController = parentResponder as? UIViewController { return viewController } } return nil } }之后在你的SKScene里这样调用:
guard let hostingVC = self.view?.parentViewController() else { print("找不到对应的ViewController") return }必填项不能漏:正确设置Popover的sourceView和sourceRect
iPad上展示UIActivityViewController时,Popover的这两个参数是强制要求的,缺一个都可能导致崩溃。你需要指定分享触发的来源视图(比如你的SKView,或者某个按钮对应的区域):// 先创建ActivityViewController let shareItems: [Any] = ["我在SpriteKit游戏里的分享内容!"] let activityVC = UIActivityViewController(activityItems: shareItems, applicationActivities: nil) // 假设你有一个SKNode作为分享按钮,先把它的坐标转换成屏幕坐标 let buttonFrame = shareButton.frame let convertedRect = self.view!.convert(buttonFrame, from: shareButton.parent!) // 配置Popover参数 activityVC.popoverPresentationController?.sourceView = self.view activityVC.popoverPresentationController?.sourceRect = convertedRect // 建议设置delegate,避免Popover展示时的潜在问题 activityVC.popoverPresentationController?.delegate = hostingVC // 最后从正确的ViewController弹出 hostingVC.present(activityVC, animated: true)UI操作必须在主线程执行
如果你的分享触发逻辑是在异步回调(比如网络请求完成后)里,一定要确保present操作在主线程跑:DispatchQueue.main.async { // 这里放弹出UIActivityViewController的代码 }SpriteKit的
didMove(to view:)是主线程,但自定义的异步任务里容易忽略这点,iPad对线程的要求比iPhone更严格。排查崩溃根源:查看设备日志
既然没有报错信息,你可以去Xcode的Window > Devices and Simulators里,选中你的iPad,查看View Device Logs,找到对应崩溃的记录,里面的调用栈会告诉你具体是哪一行代码出了问题,比瞎猜靠谱多了。
内容的提问来源于stack exchange,提问作者danialias

