ParallelWorker.swift 4.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100
  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.show(in: hudView)
  51. hud.textLabel.text = NSLocalizedString(self.titleKey, comment: "")
  52. hud.detailTextLabel.text = NSLocalizedString("_tap_to_cancel_", comment: "")
  53. hud.tapOnHUDViewBlock = { hud in
  54. self.isCancelled = true
  55. hud.dismiss()
  56. }
  57. self.hud = hud
  58. }
  59. }
  60. /// Execute
  61. /// - Parameter task: The task to execute. Needs to call `completion()` when done so the next task can be executed.
  62. func execute(task: @escaping (_ completion: @escaping () -> Void) -> Void) {
  63. completionGroup.enter()
  64. queue.async {
  65. self.semaphore.wait()
  66. guard !self.isCancelled else { return self.completionGroup.leave() }
  67. task {
  68. self.completedTasks += 1
  69. DispatchQueue.main.async {
  70. self.hud?.textLabel.text = "\(NSLocalizedString(self.titleKey, comment: "")) \(self.completedTasks) "
  71. if let totalTasks = self.totalTasks {
  72. self.hud?.textLabel.text?.append("\(NSLocalizedString("_of_", comment: "")) \(totalTasks)")
  73. } else {
  74. self.hud?.textLabel.text?.append(NSLocalizedString("_files_", comment: ""))
  75. }
  76. }
  77. self.semaphore.signal()
  78. self.completionGroup.leave()
  79. }
  80. }
  81. }
  82. /// Indicates that all tasks have been scheduled. Some tasks might still be in progress.
  83. /// - Parameter completion: Will be called after all tasks have finished
  84. func completeWork(completion: (() -> Void)? = nil) {
  85. completionGroup.notify(queue: .main) {
  86. guard !self.isCancelled else { return }
  87. self.hud?.indicatorView = JGProgressHUDSuccessIndicatorView()
  88. self.hud?.textLabel.text = NSLocalizedString("_done_", comment: "")
  89. self.hud?.detailTextLabel.text = ""
  90. self.hud?.dismiss(afterDelay: 1)
  91. completion?()
  92. }
  93. }
  94. }