Skip to content

Commit 16935f4

Browse files
author
Ruben Nine
committed
Client upload functions now return an Uploader rather than specific classes.
Turning `MutifileUpload` and `MultipartUpload` into internal classes. `Uploader`s return a `progress` property that is a mirror of the internally used one.
1 parent 92b34dd commit 16935f4

File tree

8 files changed

+221
-122
lines changed

8 files changed

+221
-122
lines changed

FilestackSDK.xcodeproj/project.pbxproj

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,8 @@
6161
4596207022BA338E00D58036 /* ImageSizeTransform.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4596206F22BA338E00D58036 /* ImageSizeTransform.swift */; };
6262
45965C6B1F20C47B005689BA /* MultipartUploadSubmitPartOperation.swift in Sources */ = {isa = PBXBuildFile; fileRef = 45965C6A1F20C47B005689BA /* MultipartUploadSubmitPartOperation.swift */; };
6363
45991FA41F14C1DD0042A279 /* ProcessService.swift in Sources */ = {isa = PBXBuildFile; fileRef = 45991FA31F14C1DD0042A279 /* ProcessService.swift */; };
64+
459B7404232F7BD5007CBC50 /* MirroredProgress.swift in Sources */ = {isa = PBXBuildFile; fileRef = 459B7403232F7BD5007CBC50 /* MirroredProgress.swift */; };
65+
459B7406232F894B007CBC50 /* Uploader.swift in Sources */ = {isa = PBXBuildFile; fileRef = 459B7405232F894B007CBC50 /* Uploader.swift */; };
6466
459E61EE1F31BBEF00237EA1 /* MultipartuploadSubmitChunkOperation.swift in Sources */ = {isa = PBXBuildFile; fileRef = 459E61ED1F31BBEF00237EA1 /* MultipartuploadSubmitChunkOperation.swift */; };
6567
45A07B3122B91A52003128B0 /* DocumentDetectionTransform.swift in Sources */ = {isa = PBXBuildFile; fileRef = 45A07B3022B91A52003128B0 /* DocumentDetectionTransform.swift */; };
6668
45B63B0423279E690040BFBB /* Uploadable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 45B63B0323279E690040BFBB /* Uploadable.swift */; };
@@ -240,6 +242,8 @@
240242
4596206F22BA338E00D58036 /* ImageSizeTransform.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ImageSizeTransform.swift; sourceTree = "<group>"; };
241243
45965C6A1F20C47B005689BA /* MultipartUploadSubmitPartOperation.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MultipartUploadSubmitPartOperation.swift; sourceTree = "<group>"; };
242244
45991FA31F14C1DD0042A279 /* ProcessService.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ProcessService.swift; sourceTree = "<group>"; };
245+
459B7403232F7BD5007CBC50 /* MirroredProgress.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MirroredProgress.swift; sourceTree = "<group>"; };
246+
459B7405232F894B007CBC50 /* Uploader.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Uploader.swift; sourceTree = "<group>"; };
243247
459E61ED1F31BBEF00237EA1 /* MultipartuploadSubmitChunkOperation.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MultipartuploadSubmitChunkOperation.swift; sourceTree = "<group>"; };
244248
45A07B3022B91A52003128B0 /* DocumentDetectionTransform.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DocumentDetectionTransform.swift; sourceTree = "<group>"; };
245249
45B63B0323279E690040BFBB /* Uploadable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Uploadable.swift; sourceTree = "<group>"; };
@@ -475,16 +479,27 @@
475479
path = Enums;
476480
sourceTree = "<group>";
477481
};
482+
459B7407232F95E1007CBC50 /* Uploaders */ = {
483+
isa = PBXGroup;
484+
children = (
485+
BCDB405120A9A87C00148136 /* MultifileUpload.swift */,
486+
45107C8B1F4D6ADC00250ABE /* MultipartUpload.swift */,
487+
);
488+
path = Uploaders;
489+
sourceTree = "<group>";
490+
};
478491
45B63AFE23279C790040BFBB /* Internal */ = {
479492
isa = PBXGroup;
480493
children = (
481494
4589A4871F0A4B1900C39405 /* Constants.swift */,
495+
459B7403232F7BD5007CBC50 /* MirroredProgress.swift */,
482496
45B66480232838C200DF5706 /* Tools.swift */,
483497
454CC1C91F0D1151005821AC /* Extensions */,
484498
4502F71E1F1F4C28000875D6 /* Operations */,
485499
45B63B0123279E3F0040BFBB /* Protocols */,
486500
45FA0CC91F0B86B6008EDBCD /* Services */,
487501
45B63B0D23279F810040BFBB /* Uploadable Readers */,
502+
459B7407232F95E1007CBC50 /* Uploaders */,
488503
);
489504
path = Internal;
490505
sourceTree = "<group>";
@@ -515,6 +530,7 @@
515530
isa = PBXGroup;
516531
children = (
517532
45B63B0323279E690040BFBB /* Uploadable.swift */,
533+
459B7405232F894B007CBC50 /* Uploader.swift */,
518534
);
519535
path = Protocols;
520536
sourceTree = "<group>";
@@ -614,8 +630,6 @@
614630
children = (
615631
45B831211F03F1C90053742A /* Client.swift */,
616632
4589A4891F0A4DA600C39405 /* FileLink.swift */,
617-
BCDB405120A9A87C00148136 /* MultifileUpload.swift */,
618-
45107C8B1F4D6ADC00250ABE /* MultipartUpload.swift */,
619633
45F9B8C51F0BA02F00E04380 /* NetworkDataResponse.swift */,
620634
454CC1AC1F0CD8D5005821AC /* NetworkDownloadResponse.swift */,
621635
4548CA481F1CBE58009FDBEF /* NetworkJSONResponse.swift */,
@@ -902,6 +916,7 @@
902916
457D5BF31F1614D400FBD5B1 /* PolicyCall.swift in Sources */,
903917
45B63B0C23279F3D0040BFBB /* DataReader.swift in Sources */,
904918
454CC1AD1F0CD8D5005821AC /* NetworkDownloadResponse.swift in Sources */,
919+
459B7404232F7BD5007CBC50 /* MirroredProgress.swift in Sources */,
905920
BC8832E220D181A700B88EAF /* QualityTransform.swift in Sources */,
906921
BC8832DB20D181A700B88EAF /* DetectFacesTransform.swift in Sources */,
907922
45A07B3122B91A52003128B0 /* DocumentDetectionTransform.swift in Sources */,
@@ -954,6 +969,7 @@
954969
BC8832CF20D181A700B88EAF /* CropFacesTransform.swift in Sources */,
955970
BC8832F820D27A7B00B88EAF /* ASCIITransform.swift in Sources */,
956971
BC8832D920D181A700B88EAF /* PixelateFacesTransform.swift in Sources */,
972+
459B7406232F894B007CBC50 /* Uploader.swift in Sources */,
957973
45B831221F03F1C90053742A /* Client.swift in Sources */,
958974
45C3EA0F1F262ED30003598D /* MetadataOptions.swift in Sources */,
959975
);
Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
//
2+
// MirroredProgress.swift
3+
// FilestackSDK
4+
//
5+
// Created by Ruben Nine on 16/09/2019.
6+
// Copyright © 2019 Filestack. All rights reserved.
7+
//
8+
9+
import Foundation
10+
11+
/// Holds a mirrored copy of itself and its children, so the copy may be publicly returned by classes that report
12+
/// progress instead of returning the original.
13+
///
14+
/// It also sets observers on `isCancelled` and `isPaused` on the mirrored `Progress`, so the original may be
15+
/// cancelled or paused by the mirror.
16+
///
17+
/// Typically, the `MirroredProgress` object will be private, while the `mirror` may be publicly exposed by using
18+
/// a lazy property:
19+
///
20+
/// ```
21+
/// private let masterProcess = MirroredProgress()
22+
///
23+
/// public lazy var progress: Progress = {
24+
/// masterProgress.mirror
25+
/// }()
26+
/// ```
27+
class MirroredProgress: Progress {
28+
let mirror = Progress(totalUnitCount: 0)
29+
30+
var isPausedObserver: NSKeyValueObservation?
31+
var isCancelledObserver: NSKeyValueObservation?
32+
33+
// MARK: - Overrides
34+
35+
override init(parent parentProgressOrNil: Progress?, userInfo userInfoOrNil: [ProgressUserInfoKey: Any]? = nil) {
36+
super.init(parent: parentProgressOrNil, userInfo: userInfoOrNil)
37+
setMirrorObservers()
38+
}
39+
40+
override var completedUnitCount: Int64 {
41+
didSet { mirror.completedUnitCount = completedUnitCount }
42+
}
43+
44+
override var totalUnitCount: Int64 {
45+
didSet { mirror.totalUnitCount = totalUnitCount }
46+
}
47+
48+
override func addChild(_ child: Progress, withPendingUnitCount inUnitCount: Int64) {
49+
super.addChild(child, withPendingUnitCount: inUnitCount)
50+
51+
if let child = child as? MirroredProgress {
52+
mirror.addChild(child.mirror, withPendingUnitCount: inUnitCount)
53+
}
54+
}
55+
56+
// MARK: - Private Functions
57+
58+
private func setMirrorObservers() {
59+
isPausedObserver = mirror.observe(\.isPaused, options: [.new]) { _, change in
60+
if change.newValue == true {
61+
self.pause()
62+
} else {
63+
self.resume()
64+
}
65+
}
66+
67+
isCancelledObserver = mirror.observe(\.isCancelled, options: [.new]) { _, change in
68+
if change.newValue == true {
69+
self.cancel()
70+
}
71+
}
72+
}
73+
}

FilestackSDK/Public/Models/MultifileUpload.swift renamed to FilestackSDK/Internal/Uploaders/MultifileUpload.swift

Lines changed: 39 additions & 60 deletions
Original file line numberDiff line numberDiff line change
@@ -9,28 +9,13 @@
99
import Foundation
1010

1111
/// This class allows uploading multiple `Uploadable` items to a given storage location.
12-
///
13-
/// Please notice this class can not be directly instantiated. Instances of this class are
14-
/// returned by the upload functions in `Client`.
15-
///
16-
/// Features:
17-
///
18-
/// - Ability to track upload progress (see the `progress` property)
19-
/// - Ability to add `Uploadable` items at any time before the upload starts (see `add(uploadables:)`)
20-
/// - Ability to cancel the upload process (see `cancel()`)
21-
///
22-
@objc(FSMultifileUpload) public class MultifileUpload: NSObject {
12+
class MultifileUpload: Uploader, DeferredAdd {
2313
// MARK: - Public Properties
2414

25-
/// The overall upload progress.
26-
@objc public let progress = Progress()
27-
28-
/// Current upload status.
29-
@objc public private(set) var currentStatus: UploadStatus = .notStarted
30-
3115
// MARK: - Internal Properties
3216

33-
internal var uploadProgress: ((Progress) -> Void)?
17+
internal let masterProgress = MirroredProgress()
18+
internal var progressHandler: ((Progress) -> Void)?
3419
internal var completionHandler: (([NetworkJSONResponse]) -> Void)?
3520

3621
// MARK: - Private Properties
@@ -58,42 +43,29 @@ import Foundation
5843
self.apiKey = apiKey
5944
self.security = security
6045

61-
super.init()
62-
6346
if let uploadables = uploadables {
6447
enqueueUploadables(uploadables: uploadables)
6548
}
6649
}
6750

68-
// MARK: - Public Functions
69-
70-
/// Adds items to be uploaded.
71-
///
72-
/// - Important: Any items added after the upload process started will be ignored.
73-
///
74-
/// - Parameter uploadables: An array of `Uploadable` items to upload.
75-
/// - Returns: True on success, false otherwise.
76-
@discardableResult public func add(uploadables: [Uploadable]) -> Bool {
77-
switch currentStatus {
78-
case .notStarted:
79-
self.enqueueUploadables(uploadables: uploadables)
51+
// MARK: - Uploadable Protocol Implementation
8052

81-
return true
82-
default:
83-
return false
53+
private(set) var currentStatus: UploadStatus = .notStarted {
54+
didSet {
55+
switch currentStatus {
56+
case .cancelled:
57+
progress.cancel()
58+
default:
59+
break
60+
}
8461
}
8562
}
8663

87-
/// Cancels upload.
88-
///
89-
/// - Important: Any already uploaded files **will not** be deleted —
90-
/// only the current file being uploaded (if any) and any pending files will be affected.
91-
///
92-
/// On success, this will trigger `completionHandler`.
93-
///
94-
/// - Returns: True on success, false otherwise.
95-
@objc
96-
@discardableResult public func cancel() -> Bool {
64+
lazy var progress = {
65+
masterProgress.mirror
66+
}()
67+
68+
@discardableResult func cancel() -> Bool {
9769
switch currentStatus {
9870
case .notStarted:
9971
fallthrough
@@ -108,11 +80,7 @@ import Foundation
10880
}
10981
}
11082

111-
/// Starts upload.
112-
///
113-
/// - Returns: True on success, false otherwise.
114-
@objc
115-
@discardableResult public func start() -> Bool {
83+
@discardableResult func start() -> Bool {
11684
switch currentStatus {
11785
case .notStarted:
11886
uploadNextFile()
@@ -124,11 +92,22 @@ import Foundation
12492
}
12593
}
12694

127-
/// :nodoc:
128-
@available(*, deprecated, message: "Marked for removal in version 3.0. Use start() instead.")
129-
@objc public func uploadFiles() {
95+
func uploadFiles() {
13096
start()
13197
}
98+
99+
// MARK: - DeferredAdd Protocol Implementation
100+
101+
@discardableResult func add(uploadables: [Uploadable]) -> Bool {
102+
switch currentStatus {
103+
case .notStarted:
104+
self.enqueueUploadables(uploadables: uploadables)
105+
106+
return true
107+
default:
108+
return false
109+
}
110+
}
132111
}
133112

134113
private extension MultifileUpload {
@@ -144,15 +123,15 @@ private extension MultifileUpload {
144123
// Append uploads to `pendingUploads`.
145124
pendingUploads.append(contentsOf: uploads)
146125
// Update progress total unit count so it matches the `pendingUploads` count.
147-
progress.totalUnitCount = Int64(pendingUploads.count)
126+
masterProgress.totalUnitCount = Int64(pendingUploads.count)
148127

149128
// Set upload progress and completion handlers and add upload progress as a child of our main `progress` object
150129
// so we can track all uploads from our main `progress` object.
151130
for upload in uploads {
152131
upload.uploadProgress = { _ in self.updateProgress() }
153132
upload.completionHandler = { self.finishedCurrentFile(with: $0) }
154133

155-
progress.addChild(upload.progress, withPendingUnitCount: 1)
134+
masterProgress.addChild(upload.masterProgress, withPendingUnitCount: 1)
156135
}
157136
}
158137

@@ -171,13 +150,13 @@ private extension MultifileUpload {
171150
func stopUpload() {
172151
guard currentStatus != .completed, currentStatus != .cancelled else { return }
173152

174-
if progress.completedUnitCount == progress.totalUnitCount {
153+
if masterProgress.completedUnitCount == masterProgress.totalUnitCount {
175154
currentStatus = .completed
176155
} else {
177156
currentStatus = .cancelled
178157
}
179158

180-
while uploadResponses.count < progress.totalUnitCount {
159+
while uploadResponses.count < masterProgress.totalUnitCount {
181160
uploadResponses.append(NetworkJSONResponse(with: MultipartUploadError.aborted))
182161
}
183162

@@ -186,14 +165,14 @@ private extension MultifileUpload {
186165
// To ensure this object can be properly deallocated we must ensure that any closures are niled,
187166
// and `currentOperation` object is niled as well.
188167
self.completionHandler = nil
189-
self.uploadProgress = nil
168+
self.progressHandler = nil
190169
self.currentOperation = nil
191170
}
192171
}
193172

194173
func updateProgress() {
195174
queue.async {
196-
self.uploadProgress?(self.progress)
175+
self.progressHandler?(self.progress)
197176
}
198177
}
199178

@@ -211,7 +190,7 @@ private extension MultifileUpload {
211190

212191
extension MultifileUpload {
213192
/// :nodoc:
214-
public override var description: String {
193+
public var description: String {
215194
return Tools.describe(subject: self, only: ["currentStatus", "progress"])
216195
}
217196
}

0 commit comments

Comments
 (0)