Background
The function shareImage()
in the code below launches the UIActivityViewController
and shares an image, for example sends to Messages or saves to Photos.
After the image is shared, UIActivityViewController
finishes up, and calls the completionWithItemsHandler
function activityComplete()
.
The code works fine and as expected on iOS / iPadOS / MacOS and shares the image, EXCEPT that on MacOS, the completionWithItemsHandler
function activityComplete()
never gets called, confirmed using the flag print("Share complete.")
.
Xcode instead logs the following output:
Scene destruction request failed with error: (null)
Question
What could be causing the issue preventing the completionWithItemsHandler
function activityComplete()
from being called on MacOS, and how can this be corrected in code?
Code
Note: Updated with two lines added based on the answer.
import UIKit
class ViewController: UIViewController {
var shareButton = UIButton(type: UIButton.ButtonType.custom)
var activityImage: UIImage!
override func viewDidLoad() {
super.viewDidLoad()
// Create share button
shareButton.setTitle("Share", for:UIControl.State())
shareButton.setTitleColor(.white, for: UIControl.State())
shareButton.backgroundColor = .purple
shareButton.frame = CGRect(x: 50, y: 100, width: 200, height: 200)
shareButton.addTarget(self, action: #selector(ViewController.shareImage), for:.touchUpInside)
view.addSubview(shareButton)
}
private var activity: UIActivityViewController? // <-- Added
@objc func shareImage() {
// Take view screenshot
UIGraphicsBeginImageContextWithOptions(self.view.frame.size, false, 0)
self.view.drawHierarchy(in: CGRect(x: 0, y: 0, width: self.view.bounds.width, height: self.view.bounds.height), afterScreenUpdates: false)
activityImage = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
// Share view screenshot
let activity = UIActivityViewController(activityItems: [activityImage as Any], applicationActivities: nil)
// Present iPhone share options
if UIDevice.current.userInterfaceIdiom == .phone {
self.present(activity, animated: true, completion: nil)
}
// Present iPad share options
if UIDevice.current.userInterfaceIdiom == .pad {
self.present(activity, animated: true, completion: nil)
if let popOver = activity.popoverPresentationController {
popOver.sourceView = self.shareButton
}
}
// Complete share
activity.completionWithItemsHandler = {activity, success, items, error in
self.activityComplete()
}
self.activity = activity // <-- Added
}
func activityComplete() {
print("Share complete.")
}
}
Try to retain your activity view controller after presenting it. Something like:
private var activityViewController: UIActivityViewController?
@objc func presentActivityViewController(activityItems: [Any]) {
let activityViewController = UIActivityViewController(activityItems: activityItems, applicationActivities: nil)
self.present(activityViewController, animated: true, completion: nil)
activityViewController.completionWithItemsHandler = { activity, success, items, error in
// some logic
}
self.activityViewController = activityViewController // <- retaining activityViewController
}