Skip to content

Instantly share code, notes, and snippets.

@myurieff
Created September 26, 2019 14:45
Show Gist options
  • Save myurieff/b239035204f1a3d088faa3467f9a5d1b to your computer and use it in GitHub Desktop.
Save myurieff/b239035204f1a3d088faa3467f9a5d1b to your computer and use it in GitHub Desktop.
Async activity item. How to provide data to share after the activityController is presented and the activityType is selected.
import UIKit
/// Allows for asynchronously providing an item that will be shared
/// in an UIActivityViewController instance.
///
/// ### Usage: ###
/// ```
/// let activityItem = AsyncActivityItemProvider(placeholderItem: placeholderItem) { [weak self] (activityType, handler) in
/// // ⚠️ We're in a background thread.
///
/// // ⏱ Here is a good place to kick off any
/// // progress indication.
/// self?.isInProgress = true
///
/// // 🔨 Perform the actions that will output
/// // the item you want to share.
/// // You can use the activityType parameter
/// // if you care which option is selected.
/// SomeNetworkQuery(shareOption: activityType)
/// .request { result in
/// switch result {
/// case .success(let data):
/// // ✅ When the work is done,
/// // call the handler with the result.
/// handler(data)
/// self?.isInProgress = false
/// case .failure(let error):
/// {...}
/// }
/// }
/// }
///
/// // 💬 Show the share sheet.
/// let activityViewController = UIActivityViewController(activityItems: [activityItem], applicationActivities: nil)
/// present(activityViewController, animated: true, completion: nil)
///```
final class AsyncActivityItemProvider: UIActivityItemProvider {
typealias ItemBuilder = (UIActivity.ActivityType?, (@escaping (Any) -> Void)) -> Void
private var semaphore: DispatchSemaphore?
private let itemBuilder: ItemBuilder
init(placeholderItem: Any, itemBuilder: @escaping ItemBuilder) {
self.itemBuilder = itemBuilder
super.init(placeholderItem: placeholderItem)
}
override var item: Any {
semaphore = DispatchSemaphore(value: 0)
var result: Any?
let handler: (Any) -> Void = { [weak self] itemValue in
result = itemValue
self?.semaphore?.signal()
}
itemBuilder(activityType, handler)
// Block the thread for up to 5 seconds and cancel
// in case of a timeout
if semaphore?.wait(timeout: .now() + .seconds(5)) == .timedOut {
cancel()
}
semaphore = nil
return result ?? super.item
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment