| 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..3fa081241dc8aab5abd3f292153b0df9f795df29 100644
|
| --- a/ios/chrome/app/deferred_initialization_runner.mm
|
| +++ b/ios/chrome/app/deferred_initialization_runner.mm
|
| @@ -6,7 +6,9 @@
|
|
|
| #include <stdint.h>
|
|
|
| +#import "base/ios/weak_nsobject.h"
|
| #include "base/logging.h"
|
| +#include "base/mac/scoped_block.h"
|
| #include "base/mac/scoped_nsobject.h"
|
|
|
| // An object encapsulating the deferred execution of a block of initialization
|
| @@ -15,50 +17,56 @@
|
| // A string to reference the initialization block.
|
| base::scoped_nsobject<NSString> _name;
|
| // A block of code to execute.
|
| - base::scoped_nsprotocol<ProceduralBlock> _runBlock;
|
| + base::mac::ScopedBlock<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) {
|
| _name.reset([name copy]);
|
| - _runBlock.reset([block copy]);
|
| + _runBlock.reset(block, base::scoped_policy::RETAIN);
|
| }
|
| return self;
|
| }
|
|
|
| -- (void)dispatch:(NSTimeInterval)delaySeconds {
|
| - int64_t nanoseconds = delaySeconds * NSEC_PER_SEC;
|
| +- (void)run {
|
| DCHECK([NSThread isMainThread]);
|
| - dispatch_after(dispatch_time(DISPATCH_TIME_NOW, nanoseconds),
|
| - dispatch_get_main_queue(), ^() {
|
| - [self runSynchronously];
|
| - });
|
| -}
|
| -
|
| -- (void)runSynchronously {
|
| ProceduralBlock deferredBlock = _runBlock.get();
|
| if (!deferredBlock)
|
| return;
|
| @@ -72,23 +80,89 @@
|
|
|
| @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 |delay| it will automatically
|
| +// schedule the next block after |delayBetweenBlocks|.
|
| +- (void)scheduleNextBlockWithDelay:(NSTimeInterval)delay;
|
| +
|
| +// Time interval between two blocks. Default value is 200ms.
|
| +@property(nonatomic) NSTimeInterval delayBetweenBlocks;
|
| +
|
| +// Time interval before running the first block. Default value is 3s.
|
| +@property(nonatomic) NSTimeInterval delayBeforeFirstBlock;
|
| +
|
| +@end
|
| +
|
| +@implementation DeferredInitializationRunner
|
| +
|
| +@synthesize delayBetweenBlocks = _delayBetweenBlocks;
|
| +@synthesize delayBeforeFirstBlock = _delayBeforeFirstBlock;
|
| +
|
| + (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;
|
| + _delayBeforeFirstBlock = 3.0;
|
| + }
|
| return self;
|
| }
|
|
|
| +- (void)enqueueBlockNamed:(NSString*)name block:(ProceduralBlock)block {
|
| + DCHECK(name);
|
| + DCHECK([NSThread isMainThread]);
|
| + [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 scheduleNextBlockWithDelay:self.delayBeforeFirstBlock];
|
| + }
|
| +}
|
| +
|
| +- (void)scheduleNextBlockWithDelay:(NSTimeInterval)delay {
|
| + DCHECK([NSThread isMainThread]);
|
| + _isBlockScheduled = NO;
|
| + NSString* nextBlockName = [_blocksNameQueue firstObject];
|
| + if (!nextBlockName)
|
| + return;
|
| +
|
| + DeferredInitializationBlock* nextBlock =
|
| + [_runBlocks objectForKey:nextBlockName];
|
| + DCHECK(nextBlock);
|
| +
|
| + base::WeakNSObject<DeferredInitializationRunner> weakSelf(self);
|
| +
|
| + dispatch_after(
|
| + dispatch_time(DISPATCH_TIME_NOW, (int64_t)(delay * NSEC_PER_SEC)),
|
| + dispatch_get_main_queue(), ^{
|
| + [nextBlock run];
|
| + [weakSelf scheduleNextBlockWithDelay:[weakSelf delayBetweenBlocks]];
|
| + });
|
| +
|
| + _isBlockScheduled = YES;
|
| + [_blocksNameQueue removeObjectAtIndex:0];
|
| +}
|
| +
|
| - (void)runBlockNamed:(NSString*)name
|
| after:(NSTimeInterval)delaySeconds
|
| block:(ProceduralBlock)block {
|
| @@ -106,11 +180,14 @@
|
| }
|
|
|
| - (void)runBlockIfNecessary:(NSString*)name {
|
| - [[_runBlocks objectForKey:name] runSynchronously];
|
| + DCHECK([NSThread isMainThread]);
|
| + [[_runBlocks objectForKey:name] run];
|
| }
|
|
|
| - (void)cancelBlockNamed:(NSString*)name {
|
| + DCHECK([NSThread isMainThread]);
|
| DCHECK(name);
|
| + [_blocksNameQueue removeObject:name];
|
| [[_runBlocks objectForKey:name] cancel];
|
| [_runBlocks removeObjectForKey:name];
|
| }
|
|
|