Created
September 26, 2019 14:45
-
-
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.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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