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..37e9d8c9c2ce1f6b19405a3d46948927b628006a 100644 |
| --- a/ios/chrome/app/deferred_initialization_runner.mm |
| +++ b/ios/chrome/app/deferred_initialization_runner.mm |
| @@ -18,28 +18,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 +63,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,23 +77,77 @@ |
| @end |
| -@implementation DeferredInitializationRunner { |
| +@interface DeferredInitializationRunner () { |
| + base::scoped_nsobject<NSMutableArray> _blocksNameQueue; |
| base::scoped_nsobject<NSMutableDictionary> _runBlocks; |
| + BOOL isBlockScheduled; |
|
rohitrao (ping after 24h)
2016/08/08 14:07:23
Should this be _isBlockScheduled?
gambard
2016/08/08 15:02:10
Done.
|
| } |
| +// Schedule the next block to be run after |kDelayBetweenBlock|. |
| +- (void)scheduleNextBlock; |
| + |
| +@end |
| + |
| +@implementation DeferredInitializationRunner |
| + |
| +@synthesize delayBetweenBlocks = _delayBetweenBlocks; |
| + |
| + (DeferredInitializationRunner*)sharedInstance { |
| - static DeferredInitializationRunner* instance = |
| - [[DeferredInitializationRunner alloc] init]; |
| + static dispatch_once_t once = 0; |
| + static DeferredInitializationRunner* instance = nil; |
| + dispatch_once(&once, ^{ |
| + instance = [[DeferredInitializationRunner alloc] init]; |
| + }); |
| return instance; |
| } |
| - (id)init { |
| self = [super init]; |
| - if (self) |
| + if (self) { |
| + _blocksNameQueue.reset([[NSMutableArray array] retain]); |
| _runBlocks.reset([[NSMutableDictionary dictionary] retain]); |
| + isBlockScheduled = NO; |
| + _delayBetweenBlocks = 0.2; |
| + } |
| 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)(self.delayBetweenBlocks * NSEC_PER_SEC)), |
| + dispatch_get_main_queue(), ^{ |
| + [nextBlock run]; |
| + [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
|
| + }); |
| + |
| + isBlockScheduled = YES; |
| + [_blocksNameQueue removeObjectAtIndex:0]; |
| + } |
| +} |
| + |
| - (void)runBlockNamed:(NSString*)name |
| after:(NSTimeInterval)delaySeconds |
| block:(ProceduralBlock)block { |
| @@ -106,11 +165,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]; |
| } |