5

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.")
    }
}
user4806509
  • 2,925
  • 5
  • 37
  • 72

1 Answers1

5

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
    }
Sahey
  • 264
  • 3
  • 9
  • Thank you. Could you please elaborate on what you mean by "retain your activity view controller after presenting it"? What is missing in my code, that works fine on iOS and iPadOS but not on macOS? – user4806509 Sep 14 '22 at 18:23
  • 1
    Hey! I mean to set a local instance of UIActivityViewController to a private property in presenting view controller. Please check my updated comment with a code sample. – Sahey Sep 16 '22 at 11:04
  • 1
    Perfect! Thank you so much. These two lines made all the difference: private var activityViewController: UIActivityViewController? self.activityViewController = activityViewController Thanks for showing what to update in code. – user4806509 Sep 28 '22 at 17:05
  • Yes, retaining view controller solves the issues. – sabiland May 09 '23 at 11:34