Skip to content

Commit 42d5ddf

Browse files
authored
Merge pull request #1229 from dplanitzer/operation_fixes
2 parents e23c49a + dc810f0 commit 42d5ddf

File tree

2 files changed

+29
-8
lines changed

2 files changed

+29
-8
lines changed

Foundation/Operation.swift

Lines changed: 14 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -43,13 +43,15 @@ open class Operation : NSObject {
4343
}
4444

4545
open func start() {
46-
lock.lock()
47-
_executing = true
48-
lock.unlock()
49-
main()
50-
lock.lock()
51-
_executing = false
52-
lock.unlock()
46+
if !isCancelled {
47+
lock.lock()
48+
_executing = true
49+
lock.unlock()
50+
main()
51+
lock.lock()
52+
_executing = false
53+
lock.unlock()
54+
}
5355
finish()
5456
}
5557

@@ -79,9 +81,13 @@ open class Operation : NSObject {
7981
}
8082

8183
open func cancel() {
84+
// Note that calling cancel() is advisory. It is up to the main() function to
85+
// call isCancelled at appropriate points in its execution flow and to do the
86+
// actual canceling work. Eventually main() will invoke finish() and this is
87+
// where we then leave the groups and unblock other operations that might
88+
// depend on us.
8289
lock.lock()
8390
_cancelled = true
84-
_leaveGroups()
8591
lock.unlock()
8692
}
8793

TestFoundation/TestOperationQueue.swift

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ class TestOperationQueue : XCTestCase {
2828
("test_MainQueueGetter", test_MainQueueGetter),
2929
("test_CurrentQueueOnMainQueue", test_CurrentQueueOnMainQueue),
3030
("test_CurrentQueueOnBackgroundQueue", test_CurrentQueueOnBackgroundQueue),
31+
("test_CurrentQueueOnBackgroundQueueWithSelfCancel", test_CurrentQueueOnBackgroundQueueWithSelfCancel),
3132
("test_CurrentQueueWithCustomUnderlyingQueue", test_CurrentQueueWithCustomUnderlyingQueue),
3233
("test_CurrentQueueWithUnderlyingQueueResetToNil", test_CurrentQueueWithUnderlyingQueueResetToNil),
3334
]
@@ -135,6 +136,20 @@ class TestOperationQueue : XCTestCase {
135136
waitForExpectations(timeout: 1)
136137
}
137138

139+
func test_CurrentQueueOnBackgroundQueueWithSelfCancel() {
140+
let operationQueue = OperationQueue()
141+
operationQueue.maxConcurrentOperationCount = 1
142+
let expectation = self.expectation(description: "Background execution")
143+
operationQueue.addOperation {
144+
XCTAssertEqual(operationQueue, OperationQueue.current)
145+
expectation.fulfill()
146+
// Canceling operation X from inside operation X should not cause the app to a crash
147+
operationQueue.cancelAllOperations()
148+
}
149+
150+
waitForExpectations(timeout: 1)
151+
}
152+
138153
func test_CurrentQueueWithCustomUnderlyingQueue() {
139154
let expectation = self.expectation(description: "Background execution")
140155

0 commit comments

Comments
 (0)