Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings
This repository was archived by the owner on Jul 5, 2024. It is now read-only.
/OperationPlusPublic archive

Commit1cf013d

Browse files
Merge pull request#10 from ChimeHQ/feature/timeout-improvements
Timeout improvements
2 parentseb5d3c1 +7baf9cc commit1cf013d

File tree

10 files changed

+163
-51
lines changed

10 files changed

+163
-51
lines changed

‎OperationPlus.xcodeproj/project.pbxproj‎

Lines changed: 4 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
C949420F232C7C8700BCFC88 /* AsyncBlockProducerOperation.swift in Sources */ = {isa = PBXBuildFile; fileRef = C949420E232C7C8700BCFC88 /* AsyncBlockProducerOperation.swift */; };
1515
C9494211232DB95000BCFC88 /* AsyncBlockConsumerProducerOperation.swift in Sources */ = {isa = PBXBuildFile; fileRef = C9494210232DB95000BCFC88 /* AsyncBlockConsumerProducerOperation.swift */; };
1616
C9494213232DBEE900BCFC88 /* BlockConsumerProducerOperation.swift in Sources */ = {isa = PBXBuildFile; fileRef = C9494212232DBEE900BCFC88 /* BlockConsumerProducerOperation.swift */; };
17+
C990C94423CF79D600203A47 /* NeverFinishingProducerOperation.swift in Sources */ = {isa = PBXBuildFile; fileRef = C990C94323CF79D600203A47 /* NeverFinishingProducerOperation.swift */; };
1718
C9B0213B2203CE91006A1D9F /* OperationPlus.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = C9B021312203CE91006A1D9F /* OperationPlus.framework */; };
1819
C9B021422203CE91006A1D9F /* OperationPlus.h in Headers */ = {isa = PBXBuildFile; fileRef = C9B021342203CE91006A1D9F /* OperationPlus.h */; settings = {ATTRIBUTES = (Public, ); }; };
1920
C9B0214C2203CFD1006A1D9F /* BaseOperation.swift in Sources */ = {isa = PBXBuildFile; fileRef = C9B0214B2203CFD1006A1D9F /* BaseOperation.swift */; };
@@ -72,6 +73,7 @@
7273
C949420E232C7C8700BCFC88 /* AsyncBlockProducerOperation.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AsyncBlockProducerOperation.swift; sourceTree = "<group>"; };
7374
C9494210232DB95000BCFC88 /* AsyncBlockConsumerProducerOperation.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AsyncBlockConsumerProducerOperation.swift; sourceTree = "<group>"; };
7475
C9494212232DBEE900BCFC88 /* BlockConsumerProducerOperation.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BlockConsumerProducerOperation.swift; sourceTree = "<group>"; };
76+
C990C94323CF79D600203A47 /* NeverFinishingProducerOperation.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NeverFinishingProducerOperation.swift; sourceTree = "<group>"; };
7577
C9B021312203CE91006A1D9F /* OperationPlus.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = OperationPlus.framework; sourceTree = BUILT_PRODUCTS_DIR; };
7678
C9B021342203CE91006A1D9F /* OperationPlus.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = OperationPlus.h; sourceTree = "<group>"; };
7779
C9B021352203CE91006A1D9F /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
@@ -202,6 +204,7 @@
202204
C9B021872203D3A2006A1D9F /* NeverFinishingOperation.swift */,
203205
C9B021852203D3A1006A1D9F /* OperationExpectation.swift */,
204206
C9B021842203D310006A1D9F /* OperationTestingPlus.xcconfig */,
207+
C990C94323CF79D600203A47 /* NeverFinishingProducerOperation.swift */,
205208
);
206209
path = OperationTestingPlus;
207210
sourceTree = "<group>";
@@ -407,6 +410,7 @@
407410
isa = PBXSourcesBuildPhase;
408411
buildActionMask = 2147483647;
409412
files = (
413+
C990C94423CF79D600203A47 /* NeverFinishingProducerOperation.swift in Sources */,
410414
C9B021882203D3A2006A1D9F /* OperationExpectation.swift in Sources */,
411415
C9B0218A2203D3A2006A1D9F /* NeverFinishingOperation.swift in Sources */,
412416
C9B021892203D3A2006A1D9F /* FulfillExpectationOperation.swift in Sources */,
@@ -565,7 +569,6 @@
565569
CODE_SIGN_IDENTITY = "";
566570
CODE_SIGN_STYLE = Automatic;
567571
COMBINE_HIDPI_IMAGES = YES;
568-
CURRENT_PROJECT_VERSION = 7;
569572
DEFINES_MODULE = YES;
570573
DYLIB_COMPATIBILITY_VERSION = 1;
571574
DYLIB_CURRENT_VERSION = 1;
@@ -577,7 +580,6 @@
577580
"@executable_path/../Frameworks",
578581
"@loader_path/Frameworks",
579582
);
580-
MARKETING_VERSION = 1.4.0;
581583
SKIP_INSTALL = YES;
582584
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
583585
SWIFT_VERSION = 5.0;
@@ -592,7 +594,6 @@
592594
CODE_SIGN_IDENTITY = "";
593595
CODE_SIGN_STYLE = Automatic;
594596
COMBINE_HIDPI_IMAGES = YES;
595-
CURRENT_PROJECT_VERSION = 7;
596597
DEFINES_MODULE = YES;
597598
DYLIB_COMPATIBILITY_VERSION = 1;
598599
DYLIB_CURRENT_VERSION = 1;
@@ -604,7 +605,6 @@
604605
"@executable_path/../Frameworks",
605606
"@loader_path/Frameworks",
606607
);
607-
MARKETING_VERSION = 1.4.0;
608608
SKIP_INSTALL = YES;
609609
SWIFT_VERSION = 5.0;
610610
};
@@ -650,7 +650,6 @@
650650
CODE_SIGN_IDENTITY = "";
651651
CODE_SIGN_STYLE = Automatic;
652652
COMBINE_HIDPI_IMAGES = YES;
653-
CURRENT_PROJECT_VERSION = 6;
654653
DEFINES_MODULE = YES;
655654
DYLIB_COMPATIBILITY_VERSION = 1;
656655
DYLIB_CURRENT_VERSION = 1;
@@ -662,7 +661,6 @@
662661
"@executable_path/../Frameworks",
663662
"@loader_path/Frameworks",
664663
);
665-
MARKETING_VERSION = 1.3.0;
666664
SKIP_INSTALL = YES;
667665
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
668666
SWIFT_VERSION = 5.0;
@@ -677,7 +675,6 @@
677675
CODE_SIGN_IDENTITY = "";
678676
CODE_SIGN_STYLE = Automatic;
679677
COMBINE_HIDPI_IMAGES = YES;
680-
CURRENT_PROJECT_VERSION = 6;
681678
DEFINES_MODULE = YES;
682679
DYLIB_COMPATIBILITY_VERSION = 1;
683680
DYLIB_CURRENT_VERSION = 1;
@@ -689,7 +686,6 @@
689686
"@executable_path/../Frameworks",
690687
"@loader_path/Frameworks",
691688
);
692-
MARKETING_VERSION = 1.3.0;
693689
SKIP_INSTALL = YES;
694690
SWIFT_VERSION = 5.0;
695691
};

‎OperationPlus/BaseOperation.swift‎

Lines changed: 46 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -13,12 +13,12 @@ open class BaseOperation : Operation {
1313
case notStarted
1414
case running
1515
case finished
16-
case timedOut
1716
}
1817

1918
privateletlock:NSRecursiveLock
2019
privatevarstate:State=.notStarted
2120
publiclettimeoutInterval:TimeInterval
21+
privatevarhasTimedOut:Bool=false
2222

2323
publicinit(timeout:TimeInterval=.greatestFiniteMagnitude){
2424
self.lock=NSRecursiveLock()
@@ -48,26 +48,50 @@ open class BaseOperation : Operation {
4848
lock.lock()
4949
defer{ lock.unlock()}
5050

51-
return state==.finished || state==.timedOut
51+
return state==.finished
5252
}
5353

54+
openvarisTimedOut:Bool{
55+
lock.lock()
56+
defer{ lock.unlock()}
57+
58+
return hasTimedOut
59+
}
60+
61+
privatefunc markTimedOut(){
62+
lock.lock()
63+
defer{ lock.unlock()}
64+
65+
if isFinished{
66+
return
67+
}
68+
69+
hasTimedOut=true
70+
timedOut()
71+
}
72+
73+
/// Called when an operation times out.
74+
///
75+
/// This is a useful hook for subclassers. By default, this will call cancel() and then finish(). If you
76+
/// do override this method, be sure to either call super or explicitly finish the operation.
5477
openfunc timedOut(){
55-
transition(to:.timedOut)
78+
cancel()
79+
finish()
5680
}
5781

58-
funcprepareForMain(){
82+
funcbeginExecution(){
5983
transition(to:.running)
6084

6185
setupTimeout()
6286
}
6387

6488
overrideopenfunc start(){
89+
beginExecution()
90+
6591
ifcheckForCancellation(){
6692
return
6793
}
6894

69-
prepareForMain()
70-
7195
main()
7296
}
7397

@@ -90,13 +114,6 @@ open class BaseOperation : Operation {
90114
}
91115

92116
extensionBaseOperation{
93-
publicvarisTimedOut:Bool{
94-
lock.lock()
95-
defer{ lock.unlock()}
96-
97-
return state==.timedOut
98-
}
99-
100117
privatevardeadlineTime:DispatchTime{
101118
returnDispatchTime.now()+.seconds(Int(timeoutInterval))
102119
}
@@ -106,18 +123,31 @@ extension BaseOperation {
106123
return
107124
}
108125

126+
guard !isCancelledelse{
127+
return
128+
}
129+
109130
DispatchQueue.global().asyncAfter(deadline: deadlineTime){[weak self]in
110131
guardlet op=selfelse{
111132
return
112133
}
113134

114-
op.timedOut()
135+
op.markTimedOut()
115136
}
116137
}
117138
}
118139

119140
extensionBaseOperation{
120141
publicfunc finish(){
142+
lock.lock()
143+
defer{ lock.unlock()}
144+
145+
// If we've timed out, it's still likely that finish
146+
// is going to be called again. We should be ok with that.
147+
if isTimedOut && isFinished{
148+
return
149+
}
150+
121151
transition(to:.finished)
122152
}
123153

@@ -127,12 +157,6 @@ extension BaseOperation {
127157
returntrue
128158
}
129159

130-
// this is just a guard to protect against
131-
// accidental early finishes
132-
if isFinished{
133-
returntrue
134-
}
135-
136160
returnfalse
137161
}
138162

@@ -145,17 +169,13 @@ extension BaseOperation {
145169
willChangeValue(forKey:"isExecuting")
146170
state= newState;
147171
didChangeValue(forKey:"isExecuting")
148-
case(.running,.finished),(.running,.timedOut):
172+
case(.running,.finished):
149173
willChangeValue(forKey:"isExecuting")
150174
willChangeValue(forKey:"isFinished")
151175
state= newState;
152176
didChangeValue(forKey:"isFinished")
153177
didChangeValue(forKey:"isExecuting")
154-
case(.finished,.timedOut),(.timedOut,.finished):
155-
break
156-
case(_,.notStarted):
157-
fallthrough
158-
case(.finished, _),(.timedOut, _),(.running, _),(.notStarted, _):
178+
case(_,.notStarted),(.finished, _),(.running, _),(.notStarted, _):
159179
handleError(.stateTransitionInvalid(newState))
160180
}
161181
}

‎OperationPlus/OperationPlus.xcconfig‎

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,8 @@
1414
PRODUCT_NAME = OperationPlus
1515
PRODUCT_BUNDLE_IDENTIFIER = com.chimehq.OperationPlus
1616
PRODUCT_MODULE_NAME = OperationPlus
17-
CURRENT_PROJECT_VERSION = 7
17+
CURRENT_PROJECT_VERSION = 8
18+
MARKETING_VERSION = 1.5.0
1819

1920
INFOPLIST_FILE = OperationPlus/Info.plist
2021

‎OperationPlus/ProducerOperation.swift‎

Lines changed: 26 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -15,10 +15,16 @@ import Foundation
1515
publictypealiasResultOperation<T>=ProducerOperation<T>
1616

1717
openclassProducerOperation<T>:BaseOperation{
18+
publicenumResultCompletionBlockBehavior{
19+
case onCompletionOnly
20+
case onTimeOut(T)
21+
}
22+
1823
publictypealiasResultBlock=(T)->Void
1924

2025
publicvarresultCompletionBlock:ResultBlock?
2126
publicvarvalue:T?
27+
publicvarresultCompletionBlockBehavior=ResultCompletionBlockBehavior.onCompletionOnly
2228

2329
/// Block to return a cached value
2430
///
@@ -39,27 +45,42 @@ open class ProducerOperation<T> : BaseOperation {
3945
self.value= v
4046
writeCacheBlock?(v)
4147

42-
letinvokeBlock= !(isCancelled || isTimedOut)
43-
44-
if invokeBlock{
48+
switch(resultCompletionBlockBehavior, isCancelled, isTimedOut){
49+
case(_,false,false):
4550
resultCompletionBlock?(v)
51+
case(_, _,true):
52+
return // do not call finish in this case
53+
default:
54+
break
4655
}
4756

4857
finish()
4958
}
5059

5160
overrideopenfunc start(){
61+
beginExecution()
62+
5263
ifcheckForCancellation(){
5364
return
5465
}
5566

56-
prepareForMain()
57-
5867
iflet v=readCacheBlock?(){
5968
self.finish(with: v)
6069
return
6170
}
6271

6372
main()
6473
}
74+
75+
overrideopenfunc timedOut(){
76+
super.timedOut()
77+
78+
switch(resultCompletionBlockBehavior, isCancelled, isTimedOut){
79+
case(.onTimeOut(let v), _,true):
80+
self.value= v
81+
resultCompletionBlock?(v)
82+
default:
83+
break
84+
}
85+
}
6586
}

‎OperationPlusTests/AsyncBlockOperationTests.swift‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ class AsyncBlockOperationTests: XCTestCase {
3434
letexpectation=OperationExpectation(operation: op)
3535
expectation.isInverted=true
3636

37-
wait(for:[expectation], timeout:1.0)
37+
wait(for:[expectation], timeout:0.1)
3838

3939
XCTAssertTrue(op.isReady)
4040
XCTAssertFalse(op.isFinished)

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp