ParallelWorker.swift 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106
  1. //
  2. // ParallelWorker.swift
  3. // Nextcloud
  4. //
  5. // Created by Henrik Storch on 18.02.22.
  6. // Copyright © 2022 Henrik Storch. All rights reserved.
  7. //
  8. // Author Henrik Storch <henrik.storch@nextcloud.com>
  9. //
  10. // This program is free software: you can redistribute it and/or modify
  11. // it under the terms of the GNU General Public License as published by
  12. // the Free Software Foundation, either version 3 of the License, or
  13. // (at your option) any later version.
  14. //
  15. // This program is distributed in the hope that it will be useful,
  16. // but WITHOUT ANY WARRANTY; without even the implied warranty of
  17. // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  18. // GNU General Public License for more details.
  19. //
  20. // You should have received a copy of the GNU General Public License
  21. // along with this program. If not, see <http://www.gnu.org/licenses/>.
  22. //
  23. import UIKit
  24. import JGProgressHUD
  25. /// Object to execute multiple tasks in parallel like uploading or downloading.
  26. /// - Can display a progress indicator with status message
  27. /// - Can be canceled by user
  28. class ParallelWorker {
  29. let completionGroup = DispatchGroup()
  30. let queue = DispatchQueue(label: "ParallelWorker")
  31. let semaphore: DispatchSemaphore
  32. let titleKey: String
  33. var hud: JGProgressHUD?
  34. var totalTasks: Int?
  35. var completedTasks = 0
  36. var isCancelled = false
  37. /// Creates a ParallelWorker
  38. /// - Parameters:
  39. /// - n: Amount of tasks to be executed in parallel
  40. /// - titleKey: Localized String key, used for the status. Default: *Please Wait...*
  41. /// - totalTasks: Number of total tasks, if known
  42. /// - hudView: The parent view or current view which should present the progress indicator. If `nil`, no progress indicator will be shown.
  43. init(n: Int, titleKey: String?, totalTasks: Int?, hudView: UIView?) {
  44. semaphore = DispatchSemaphore(value: n)
  45. self.totalTasks = totalTasks
  46. self.titleKey = titleKey ?? "_wait_"
  47. guard let hudView = hudView else { return }
  48. DispatchQueue.main.async {
  49. let hud = JGProgressHUD()
  50. hud.indicatorView = JGProgressHUDRingIndicatorView()
  51. if let indicatorView = hud.indicatorView as? JGProgressHUDRingIndicatorView {
  52. indicatorView.ringWidth = 1.5
  53. }
  54. hud.textLabel.text = NSLocalizedString(self.titleKey, comment: "")
  55. hud.detailTextLabel.text = NSLocalizedString("_tap_to_cancel_", comment: "")
  56. hud.show(in: hudView)
  57. hud.tapOnHUDViewBlock = { hud in
  58. self.isCancelled = true
  59. // Cancel all download / upload
  60. for uploadRequest in NCNetworking.shared.uploadRequest {
  61. uploadRequest.value.cancel()
  62. }
  63. for downloadRequest in NCNetworking.shared.downloadRequest {
  64. downloadRequest.value.cancel()
  65. }
  66. hud.dismiss()
  67. }
  68. self.hud = hud
  69. }
  70. }
  71. /// Execute
  72. /// - Parameter task: The task to execute. Needs to call `completion()` when done so the next task can be executed.
  73. func execute(task: @escaping (_ completion: @escaping () -> Void) -> Void) {
  74. completionGroup.enter()
  75. queue.async {
  76. self.semaphore.wait()
  77. guard !self.isCancelled else { return self.completionGroup.leave() }
  78. task {
  79. self.completedTasks += 1
  80. DispatchQueue.main.async {
  81. self.hud?.textLabel.text = "\(NSLocalizedString(self.titleKey, comment: ""))"
  82. }
  83. self.semaphore.signal()
  84. self.completionGroup.leave()
  85. }
  86. }
  87. }
  88. /// Indicates that all tasks have been scheduled. Some tasks might still be in progress.
  89. /// - Parameter completion: Will be called after all tasks have finished
  90. func completeWork(completion: (() -> Void)? = nil) {
  91. completionGroup.notify(queue: .main) {
  92. guard !self.isCancelled else { return }
  93. self.hud?.indicatorView = JGProgressHUDSuccessIndicatorView()
  94. self.hud?.textLabel.text = NSLocalizedString("_done_", comment: "")
  95. self.hud?.detailTextLabel.text = ""
  96. self.hud?.dismiss(afterDelay: 1)
  97. completion?()
  98. }
  99. }
  100. }