2

I'm trying to present the UIActivityViewController in multiple parts of my app by enclosing it in a helper class. The following code works fine, I can call the showActivityController() method from any other view controllers in my app, and the UIActivityViewController gets presented as expected.

My question is, do I really need to enclose the code to present the UIActivityViewController within the DispatchQueue.main.async as shown below?

I tried it without it and it works fine but I want to make sure that leaving it there won't cause any issues later on.

class HelperClass: UIViewController, UIActivityItemSource{
    static let shared = HelperClass()

    func showActivityController(){
        DispatchQueue.main.async {
            let items = [self]
            let activityController = UIActivityViewController(activityItems: items, applicationActivities: nil)
            UIApplication.shared.keyWindow?.rootViewController?.present(activityController, animated: true)
        }
    }

    func activityViewControllerPlaceholderItem(_ activityViewController: UIActivityViewController) -> Any {
        return "Return Type"
    }

    func activityViewController(_ activityViewController: UIActivityViewController, itemForActivityType activityType: UIActivity.ActivityType?) -> Any? {
        if activityType == .message{
            return "Text for iMessage"
        }else if activityType == .mail{
            return "Text for Email" 
        }else{
            return "Text for all other apps"
        }
    }
    func activityViewController(_ activityViewController: UIActivityViewController, subjectForActivityType activityType: UIActivity.ActivityType?) -> String {
        return "Email Subject"
    }
}

Usage from other View Controllers

HelperClass.shared.showActivityController()
fs_tigre
  • 10,650
  • 13
  • 73
  • 146

2 Answers2

2

You don't need when you are in main thread only. So writing DispatchQueue is redundant

But in case if you want to present from another thread it will be a must for you presenting the UI using DispathchQueue

Suppose , you are making a network call and and after the completion of network call you have to show UI

From my point of view, you should remove the dispatch queue from the method.

func showActivityController(){
         let items = [self]
            let activityController = UIActivityViewController(activityItems: items, applicationActivities: nil)
            UIApplication.shared.keyWindow?.rootViewController?.present(activityController, animated: true)
    }

But when you have to present the UI from other thread, just call the method in main thread

DispatchQueue.main.async {
    HelperClass.shared.showActivityController()   
}
Ankur Lahiry
  • 2,253
  • 1
  • 15
  • 25
  • @ Ankur Lahiry - So, calling `DispatchQueue` the way I have it does not have the same effect as calling it as you're suggesting, it needs to be called from within the view controller that will be presenting it? `DispatchQueue.main.async { HelperClass.shared.showActivityController() } ` – fs_tigre May 21 '20 at 15:12
  • 1
    @fs_tigre lets say two cases. first, you press a button and another view is presented. second, you press a button , an api call created and you present the view when the api is end. in first case, you are surly on main thread, so no need to call the DispatchQueue. In case of second case, api call takes some time, but the thread execution isn't stopped, it is still doing other tasks. So when the API call is done, you say something like "Hey main thread you have to show a viewController now, come on", and so you do this by calling DispatchQueue block. – Ankur Lahiry May 21 '20 at 16:22
  • Make sense, I just thought that by calling it as I currently have it would be as calling it from other view controllers but I got it now, DispatchQueue must be called from the controller that will be presenting the view. Thanks – fs_tigre May 21 '20 at 16:29
1

Better to keep all interface related code on the main thread, so I would leave it with the DispatchQueue.main.async as at some point you can call showActivityController() from closure that is executed on a background thread causing runtime error. Calling DispatchQueue.main.async is safer and not causing any overhead until you call this method million times in a row.

serg_zhd
  • 1,023
  • 14
  • 26
  • Thanks a lot for your input and even though you are correct with your statement that all interface code must be kept in the main thread I think makes more sense to remove DispatchQueue and call it directly from the view controller that will be presenting the UIActivityController in stead. Thanks – fs_tigre May 21 '20 at 16:34
  • 1
    @fs_tigre it's all up to you, there is no functional difference in using this block in `HelperClass` or in `view controller` it's just saves you some typing. Best regards. – serg_zhd May 21 '20 at 17:15
  • Hmm so, it doesn't matter? If it doesn't matter, it's probably safer to keep in in the `HelperClass` that way if for some reason I forget to call `DispatchQueue` when calling `showActivityController()` from other view controllers it will not be a problem. Is there a way to test it to make sure calling `DispatchQueue` from the `HelperClass` is enough? – fs_tigre May 21 '20 at 17:23