Chromium Code Reviews| Index: ios/chrome/app/deferred_initialization_runner.mm |
| diff --git a/ios/chrome/app/deferred_initialization_runner.mm b/ios/chrome/app/deferred_initialization_runner.mm |
| index 4f537ff20964701b433a873ef8775853e21d1676..9ffe89e1e1b91332ec9fc501de677c76ed042155 100644 |
| --- a/ios/chrome/app/deferred_initialization_runner.mm |
| +++ b/ios/chrome/app/deferred_initialization_runner.mm |
| @@ -9,6 +9,11 @@ |
| #include "base/logging.h" |
| #include "base/mac/scoped_nsobject.h" |
| +namespace { |
| +// Interval between two blocks. |
| +const NSTimeInterval kDelayBetweenBlock = 0.2; |
|
gambard
2016/08/05 09:47:57
There are 18 current calls to this class ranging f
|
| +} // namespace |
| + |
| // An object encapsulating the deferred execution of a block of initialization |
| // code. |
| @interface DeferredInitializationBlock : NSObject { |
| @@ -18,28 +23,42 @@ |
| base::scoped_nsprotocol<ProceduralBlock> _runBlock; |
| } |
| +- (instancetype)init NS_UNAVAILABLE; |
| + |
| // Designated initializer. |
| -- (id)initWithName:(NSString*)name block:(ProceduralBlock)block; |
| +- (instancetype)initWithName:(NSString*)name |
| + block:(ProceduralBlock)block NS_DESIGNATED_INITIALIZER; |
| // Dispatches the deferred execution the block after |delaySeconds|. |
| +// Deprecated. |
| - (void)dispatch:(NSTimeInterval)delaySeconds; |
| // Executes the deferred block now. |
| -- (void)runSynchronously; |
| +- (void)run; |
| // Cancels the block's execution. |
| - (void)cancel; |
| + |
| @end |
| @implementation DeferredInitializationBlock |
| // Overrides default designated initializer. |
| -- (id)init { |
| +- (instancetype)init { |
| NOTREACHED(); |
| return nil; |
| } |
| -- (id)initWithName:(NSString*)name block:(ProceduralBlock)block { |
| +- (void)dispatch:(NSTimeInterval)delaySeconds { |
| + int64_t nanoseconds = delaySeconds * NSEC_PER_SEC; |
| + DCHECK([NSThread isMainThread]); |
| + dispatch_after(dispatch_time(DISPATCH_TIME_NOW, nanoseconds), |
| + dispatch_get_main_queue(), ^() { |
| + [self run]; |
| + }); |
| +} |
| + |
| +- (instancetype)initWithName:(NSString*)name block:(ProceduralBlock)block { |
| DCHECK(block); |
| self = [super init]; |
| if (self) { |
| @@ -49,16 +68,7 @@ |
| return self; |
| } |
| -- (void)dispatch:(NSTimeInterval)delaySeconds { |
| - int64_t nanoseconds = delaySeconds * NSEC_PER_SEC; |
| - DCHECK([NSThread isMainThread]); |
| - dispatch_after(dispatch_time(DISPATCH_TIME_NOW, nanoseconds), |
| - dispatch_get_main_queue(), ^() { |
| - [self runSynchronously]; |
| - }); |
| -} |
| - |
| -- (void)runSynchronously { |
| +- (void)run { |
| ProceduralBlock deferredBlock = _runBlock.get(); |
| if (!deferredBlock) |
| return; |
| @@ -72,10 +82,19 @@ |
| @end |
| -@implementation DeferredInitializationRunner { |
| +@interface DeferredInitializationRunner () { |
| + base::scoped_nsobject<NSMutableArray> _blocksNameQueue; |
| base::scoped_nsobject<NSMutableDictionary> _runBlocks; |
| + BOOL isBlockScheduled; |
| } |
| +// Schedule the next block to be run after |kDelayBetweenBlock|. |
| +- (void)scheduleNextBlock; |
| + |
| +@end |
| + |
| +@implementation DeferredInitializationRunner |
| + |
| + (DeferredInitializationRunner*)sharedInstance { |
| static DeferredInitializationRunner* instance = |
| [[DeferredInitializationRunner alloc] init]; |
| @@ -84,11 +103,49 @@ |
| - (id)init { |
| self = [super init]; |
| - if (self) |
| + if (self) { |
| + _blocksNameQueue.reset([[NSMutableArray array] retain]); |
| _runBlocks.reset([[NSMutableDictionary dictionary] retain]); |
| + isBlockScheduled = NO; |
| + } |
| return self; |
| } |
| +- (void)enqueueBlockNamed:(NSString*)name block:(ProceduralBlock)block { |
| + DCHECK(name); |
| + [self cancelBlockNamed:name]; |
| + [_blocksNameQueue addObject:name]; |
| + |
| + base::scoped_nsobject<DeferredInitializationBlock> deferredBlock( |
| + [[DeferredInitializationBlock alloc] initWithName:name block:block]); |
| + [_runBlocks setObject:deferredBlock forKey:name]; |
| + |
| + if (!isBlockScheduled) { |
| + [self scheduleNextBlock]; |
| + } |
| +} |
| + |
| +- (void)scheduleNextBlock { |
| + isBlockScheduled = NO; |
| + if ([_blocksNameQueue count] > 0) { |
| + NSString* nextBlockName = [_blocksNameQueue firstObject]; |
| + |
| + DeferredInitializationBlock* nextBlock = |
| + [_runBlocks objectForKey:nextBlockName]; |
| + DCHECK(nextBlock); |
| + |
| + dispatch_after(dispatch_time(DISPATCH_TIME_NOW, |
| + (int64_t)(kDelayBetweenBlock * NSEC_PER_SEC)), |
| + dispatch_get_main_queue(), ^{ |
| + [nextBlock run]; |
| + [self scheduleNextBlock]; |
| + }); |
| + |
| + isBlockScheduled = YES; |
| + [_blocksNameQueue removeObjectAtIndex:0]; |
| + } |
| +} |
| + |
| - (void)runBlockNamed:(NSString*)name |
| after:(NSTimeInterval)delaySeconds |
| block:(ProceduralBlock)block { |
| @@ -106,11 +163,12 @@ |
| } |
| - (void)runBlockIfNecessary:(NSString*)name { |
| - [[_runBlocks objectForKey:name] runSynchronously]; |
| + [[_runBlocks objectForKey:name] run]; |
| } |
| - (void)cancelBlockNamed:(NSString*)name { |
| DCHECK(name); |
| + [_blocksNameQueue removeObject:name]; |
| [[_runBlocks objectForKey:name] cancel]; |
| [_runBlocks removeObjectForKey:name]; |
| } |