OLD | NEW |
---|---|
1 // Copyright 2012 The Chromium Authors. All rights reserved. | 1 // Copyright 2012 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #import "ios/chrome/app/deferred_initialization_runner.h" | 5 #import "ios/chrome/app/deferred_initialization_runner.h" |
6 | 6 |
7 #include <stdint.h> | 7 #include <stdint.h> |
8 | 8 |
9 #include "base/logging.h" | 9 #include "base/logging.h" |
10 #include "base/mac/scoped_nsobject.h" | 10 #include "base/mac/scoped_nsobject.h" |
11 | 11 |
12 // An object encapsulating the deferred execution of a block of initialization | 12 // An object encapsulating the deferred execution of a block of initialization |
13 // code. | 13 // code. |
14 @interface DeferredInitializationBlock : NSObject { | 14 @interface DeferredInitializationBlock : NSObject { |
15 // A string to reference the initialization block. | 15 // A string to reference the initialization block. |
16 base::scoped_nsobject<NSString> _name; | 16 base::scoped_nsobject<NSString> _name; |
17 // A block of code to execute. | 17 // A block of code to execute. |
18 base::scoped_nsprotocol<ProceduralBlock> _runBlock; | 18 base::scoped_nsprotocol<ProceduralBlock> _runBlock; |
19 } | 19 } |
20 | 20 |
21 - (instancetype)init NS_UNAVAILABLE; | |
22 | |
21 // Designated initializer. | 23 // Designated initializer. |
22 - (id)initWithName:(NSString*)name block:(ProceduralBlock)block; | 24 - (instancetype)initWithName:(NSString*)name |
25 block:(ProceduralBlock)block NS_DESIGNATED_INITIALIZER; | |
23 | 26 |
24 // Dispatches the deferred execution the block after |delaySeconds|. | 27 // Dispatches the deferred execution the block after |delaySeconds|. |
28 // Deprecated. | |
25 - (void)dispatch:(NSTimeInterval)delaySeconds; | 29 - (void)dispatch:(NSTimeInterval)delaySeconds; |
26 | 30 |
27 // Executes the deferred block now. | 31 // Executes the deferred block now. |
28 - (void)runSynchronously; | 32 - (void)run; |
29 | 33 |
30 // Cancels the block's execution. | 34 // Cancels the block's execution. |
31 - (void)cancel; | 35 - (void)cancel; |
36 | |
32 @end | 37 @end |
33 | 38 |
34 @implementation DeferredInitializationBlock | 39 @implementation DeferredInitializationBlock |
35 | 40 |
36 // Overrides default designated initializer. | 41 // Overrides default designated initializer. |
37 - (id)init { | 42 - (instancetype)init { |
38 NOTREACHED(); | 43 NOTREACHED(); |
39 return nil; | 44 return nil; |
40 } | 45 } |
41 | 46 |
42 - (id)initWithName:(NSString*)name block:(ProceduralBlock)block { | 47 - (void)dispatch:(NSTimeInterval)delaySeconds { |
48 int64_t nanoseconds = delaySeconds * NSEC_PER_SEC; | |
49 DCHECK([NSThread isMainThread]); | |
50 dispatch_after(dispatch_time(DISPATCH_TIME_NOW, nanoseconds), | |
51 dispatch_get_main_queue(), ^() { | |
52 [self run]; | |
53 }); | |
54 } | |
55 | |
56 - (instancetype)initWithName:(NSString*)name block:(ProceduralBlock)block { | |
43 DCHECK(block); | 57 DCHECK(block); |
44 self = [super init]; | 58 self = [super init]; |
45 if (self) { | 59 if (self) { |
46 _name.reset([name copy]); | 60 _name.reset([name copy]); |
47 _runBlock.reset([block copy]); | 61 _runBlock.reset([block copy]); |
48 } | 62 } |
49 return self; | 63 return self; |
50 } | 64 } |
51 | 65 |
52 - (void)dispatch:(NSTimeInterval)delaySeconds { | 66 - (void)run { |
53 int64_t nanoseconds = delaySeconds * NSEC_PER_SEC; | |
54 DCHECK([NSThread isMainThread]); | |
55 dispatch_after(dispatch_time(DISPATCH_TIME_NOW, nanoseconds), | |
56 dispatch_get_main_queue(), ^() { | |
57 [self runSynchronously]; | |
58 }); | |
59 } | |
60 | |
61 - (void)runSynchronously { | |
62 ProceduralBlock deferredBlock = _runBlock.get(); | 67 ProceduralBlock deferredBlock = _runBlock.get(); |
63 if (!deferredBlock) | 68 if (!deferredBlock) |
64 return; | 69 return; |
65 deferredBlock(); | 70 deferredBlock(); |
66 [[DeferredInitializationRunner sharedInstance] cancelBlockNamed:_name]; | 71 [[DeferredInitializationRunner sharedInstance] cancelBlockNamed:_name]; |
67 } | 72 } |
68 | 73 |
69 - (void)cancel { | 74 - (void)cancel { |
70 _runBlock.reset(); | 75 _runBlock.reset(); |
71 } | 76 } |
72 | 77 |
73 @end | 78 @end |
74 | 79 |
75 @implementation DeferredInitializationRunner { | 80 @interface DeferredInitializationRunner () { |
81 base::scoped_nsobject<NSMutableArray> _blocksNameQueue; | |
76 base::scoped_nsobject<NSMutableDictionary> _runBlocks; | 82 base::scoped_nsobject<NSMutableDictionary> _runBlocks; |
83 BOOL isBlockScheduled; | |
rohitrao (ping after 24h)
2016/08/08 14:07:23
Should this be _isBlockScheduled?
gambard
2016/08/08 15:02:10
Done.
| |
77 } | 84 } |
78 | 85 |
86 // Schedule the next block to be run after |kDelayBetweenBlock|. | |
87 - (void)scheduleNextBlock; | |
88 | |
89 @end | |
90 | |
91 @implementation DeferredInitializationRunner | |
92 | |
93 @synthesize delayBetweenBlocks = _delayBetweenBlocks; | |
94 | |
79 + (DeferredInitializationRunner*)sharedInstance { | 95 + (DeferredInitializationRunner*)sharedInstance { |
80 static DeferredInitializationRunner* instance = | 96 static dispatch_once_t once = 0; |
81 [[DeferredInitializationRunner alloc] init]; | 97 static DeferredInitializationRunner* instance = nil; |
98 dispatch_once(&once, ^{ | |
99 instance = [[DeferredInitializationRunner alloc] init]; | |
100 }); | |
82 return instance; | 101 return instance; |
83 } | 102 } |
84 | 103 |
85 - (id)init { | 104 - (id)init { |
86 self = [super init]; | 105 self = [super init]; |
87 if (self) | 106 if (self) { |
107 _blocksNameQueue.reset([[NSMutableArray array] retain]); | |
88 _runBlocks.reset([[NSMutableDictionary dictionary] retain]); | 108 _runBlocks.reset([[NSMutableDictionary dictionary] retain]); |
109 isBlockScheduled = NO; | |
110 _delayBetweenBlocks = 0.2; | |
111 } | |
89 return self; | 112 return self; |
90 } | 113 } |
91 | 114 |
115 - (void)enqueueBlockNamed:(NSString*)name block:(ProceduralBlock)block { | |
116 DCHECK(name); | |
117 [self cancelBlockNamed:name]; | |
118 [_blocksNameQueue addObject:name]; | |
119 | |
120 base::scoped_nsobject<DeferredInitializationBlock> deferredBlock( | |
121 [[DeferredInitializationBlock alloc] initWithName:name block:block]); | |
122 [_runBlocks setObject:deferredBlock forKey:name]; | |
123 | |
124 if (!isBlockScheduled) { | |
125 [self scheduleNextBlock]; | |
126 } | |
127 } | |
128 | |
129 - (void)scheduleNextBlock { | |
130 isBlockScheduled = NO; | |
131 if ([_blocksNameQueue count] > 0) { | |
132 NSString* nextBlockName = [_blocksNameQueue firstObject]; | |
133 | |
134 DeferredInitializationBlock* nextBlock = | |
135 [_runBlocks objectForKey:nextBlockName]; | |
136 DCHECK(nextBlock); | |
137 | |
138 dispatch_after( | |
139 dispatch_time(DISPATCH_TIME_NOW, | |
140 (int64_t)(self.delayBetweenBlocks * NSEC_PER_SEC)), | |
141 dispatch_get_main_queue(), ^{ | |
142 [nextBlock run]; | |
143 [self scheduleNextBlock]; | |
rohitrao (ping after 24h)
2016/08/08 14:07:23
Is there any chance that retaining |self| could ca
gambard
2016/08/08 15:02:10
As it was a singleton I thought it would be ok to
| |
144 }); | |
145 | |
146 isBlockScheduled = YES; | |
147 [_blocksNameQueue removeObjectAtIndex:0]; | |
148 } | |
149 } | |
150 | |
92 - (void)runBlockNamed:(NSString*)name | 151 - (void)runBlockNamed:(NSString*)name |
93 after:(NSTimeInterval)delaySeconds | 152 after:(NSTimeInterval)delaySeconds |
94 block:(ProceduralBlock)block { | 153 block:(ProceduralBlock)block { |
95 DCHECK(name); | 154 DCHECK(name); |
96 // Safety check in case this function is called with a nanosecond or | 155 // Safety check in case this function is called with a nanosecond or |
97 // microsecond parameter by mistake. | 156 // microsecond parameter by mistake. |
98 DCHECK(delaySeconds < 3600.0); | 157 DCHECK(delaySeconds < 3600.0); |
99 // Cancels the previously scheduled block, if there is one, so this | 158 // Cancels the previously scheduled block, if there is one, so this |
100 // |name| block will not be run more than once. | 159 // |name| block will not be run more than once. |
101 [[_runBlocks objectForKey:name] cancel]; | 160 [[_runBlocks objectForKey:name] cancel]; |
102 base::scoped_nsobject<DeferredInitializationBlock> deferredBlock( | 161 base::scoped_nsobject<DeferredInitializationBlock> deferredBlock( |
103 [[DeferredInitializationBlock alloc] initWithName:name block:block]); | 162 [[DeferredInitializationBlock alloc] initWithName:name block:block]); |
104 [_runBlocks setObject:deferredBlock forKey:name]; | 163 [_runBlocks setObject:deferredBlock forKey:name]; |
105 [deferredBlock dispatch:delaySeconds]; | 164 [deferredBlock dispatch:delaySeconds]; |
106 } | 165 } |
107 | 166 |
108 - (void)runBlockIfNecessary:(NSString*)name { | 167 - (void)runBlockIfNecessary:(NSString*)name { |
109 [[_runBlocks objectForKey:name] runSynchronously]; | 168 [[_runBlocks objectForKey:name] run]; |
110 } | 169 } |
111 | 170 |
112 - (void)cancelBlockNamed:(NSString*)name { | 171 - (void)cancelBlockNamed:(NSString*)name { |
113 DCHECK(name); | 172 DCHECK(name); |
173 [_blocksNameQueue removeObject:name]; | |
114 [[_runBlocks objectForKey:name] cancel]; | 174 [[_runBlocks objectForKey:name] cancel]; |
115 [_runBlocks removeObjectForKey:name]; | 175 [_runBlocks removeObjectForKey:name]; |
116 } | 176 } |
117 | 177 |
118 - (NSUInteger)numberOfBlocksRemaining { | 178 - (NSUInteger)numberOfBlocksRemaining { |
119 return [_runBlocks count]; | 179 return [_runBlocks count]; |
120 } | 180 } |
121 | 181 |
122 @end | 182 @end |
OLD | NEW |