Skip to content

Commit cb0a054

Browse files
committed
Add cancel operation feature
1 parent a289cf8 commit cb0a054

2 files changed

Lines changed: 88 additions & 5 deletions

File tree

Zip/Zip.swift

Lines changed: 23 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -17,13 +17,16 @@ public enum ZipError: Error {
1717
case unzipFail
1818
/// Zip fail
1919
case zipFail
20-
20+
/// Operation Cancelled
21+
case operationCancelled
22+
2123
/// User readable description
2224
public var description: String {
2325
switch self {
2426
case .fileNotFound: return NSLocalizedString("File not found.", comment: "")
2527
case .unzipFail: return NSLocalizedString("Failed to unzip file.", comment: "")
2628
case .zipFail: return NSLocalizedString("Failed to zip file.", comment: "")
29+
case .operationCancelled: return NSLocalizedString("Operation cancelled", comment: "")
2730
}
2831
}
2932
}
@@ -50,12 +53,16 @@ public enum ZipCompression: Int {
5053

5154
/// Zip class
5255
public class Zip {
53-
5456
/**
5557
Set of vaild file extensions
5658
*/
5759
internal static var customFileExtensions: Set<String> = []
5860

61+
/**
62+
Cancellation block. This is set once the progress tracker is has been created
63+
*/
64+
public static var cancelCurrentOperation: (()->Void) = { }
65+
5966
// MARK: Lifecycle
6067

6168
/**
@@ -113,6 +120,8 @@ public class Zip {
113120
progressTracker.isPausable = false
114121
progressTracker.kind = ProgressKind.file
115122

123+
cancelCurrentOperation = { progressTracker.cancel() }
124+
116125
// Begin unzipping
117126
let zip = unzOpen64(path)
118127
defer {
@@ -234,16 +243,19 @@ public class Zip {
234243
}
235244

236245
progressTracker.completedUnitCount = Int64(currentPosition)
237-
238-
} while (ret == UNZ_OK && ret != UNZ_END_OF_LIST_OF_FILE)
246+
247+
} while (ret == UNZ_OK && ret != UNZ_END_OF_LIST_OF_FILE) && !progressTracker.isCancelled
248+
249+
guard !progressTracker.isCancelled else {
250+
throw ZipError.operationCancelled
251+
}
239252

240253
// Completed. Update progress handler.
241254
if let progressHandler = progress{
242255
progressHandler(1.0)
243256
}
244257

245258
progressTracker.completedUnitCount = Int64(totalSize)
246-
247259
}
248260

249261
// MARK: Zip
@@ -297,6 +309,8 @@ public class Zip {
297309
progressTracker.isPausable = false
298310
progressTracker.kind = ProgressKind.file
299311

312+
cancelCurrentOperation = { progressTracker.cancel() }
313+
300314
// Begin Zipping
301315
let zip = zipOpen(destinationPath, APPEND_STATUS_CREATE)
302316
for path in processedPaths {
@@ -338,6 +352,10 @@ public class Zip {
338352
}
339353
var length: Int = 0
340354
while (feof(input) == 0) {
355+
guard !progressTracker.isCancelled else {
356+
throw ZipError.operationCancelled
357+
}
358+
341359
length = fread(buffer, 1, chunkSize, input)
342360
zipWriteInFileInZip(zip, buffer, UInt32(length))
343361
}

ZipTests/ZipTests.swift

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -315,4 +315,69 @@ class ZipTests: XCTestCase {
315315
XCTAssertTrue(Zip.isValidFileExtension("cbz"))
316316
}
317317

318+
func testCancelDuringZipCancels() {
319+
var currentProgress: Double = 0
320+
321+
let expect = expectation(description: "Zip operation should throw .OperationCancelled")
322+
323+
do {
324+
let progress = Progress()
325+
progress.totalUnitCount = 1
326+
327+
let imageURL1 = Bundle(for: ZipTests.self).url(forResource: "3crBXeO", withExtension: "gif")!
328+
let imageURL2 = Bundle(for: ZipTests.self).url(forResource: "kYkLkPf", withExtension: "gif")!
329+
let documentsFolder = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask)[0] as NSURL
330+
let zipFilePath = documentsFolder.appendingPathComponent("archive.zip")!
331+
332+
try Zip.zipFiles(paths: [imageURL1, imageURL2], zipFilePath: zipFilePath, password: nil) { progress in
333+
currentProgress = progress
334+
335+
if progress > 0 {
336+
Zip.cancelCurrentOperation()
337+
}
338+
}
339+
340+
}
341+
catch {
342+
XCTAssertEqual(error as? ZipError, .operationCancelled)
343+
XCTAssertLessThan(currentProgress, 1, "Progress should be less than 1 when cancelling the current operation")
344+
expect.fulfill()
345+
}
346+
347+
waitForExpectations(timeout: 5) { error in
348+
XCTAssertNil(error)
349+
}
350+
}
351+
352+
func testCancelDuringUnzipCancels() {
353+
var currentProgress: Double = 0
354+
let expect = expectation(description: "Unzip operation should throw .OperationCancelled")
355+
356+
do {
357+
let progress = Progress()
358+
progress.totalUnitCount = 1
359+
360+
let bookURL = Bundle(for: ZipTests.self).url(forResource: "bb8", withExtension: "zip")!
361+
let documentsFolder = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask)[0] as NSURL
362+
let zipFilePath = documentsFolder.appendingPathComponent("contents")!
363+
364+
try Zip.unzipFile(bookURL, destination: zipFilePath, overwrite: true, password: nil, progress: { progress in
365+
currentProgress = progress
366+
367+
if progress > 0 {
368+
Zip.cancelCurrentOperation()
369+
}
370+
}) { _ in }
371+
}
372+
catch {
373+
XCTAssertEqual(error as? ZipError, .operationCancelled)
374+
XCTAssertLessThan(currentProgress, 1, "Progress should be less than 1 when cancelling the current operation")
375+
expect.fulfill()
376+
}
377+
378+
waitForExpectations(timeout: 5) { error in
379+
XCTAssertNil(error)
380+
}
381+
}
382+
318383
}

0 commit comments

Comments
 (0)