| 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
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..930ad9053ec75ba685070a44bae9c6865a358257
|
| --- /dev/null
|
| +++ b/ios/chrome/app/deferred_initialization_runner.mm
|
| @@ -0,0 +1,116 @@
|
| +// Copyright 2012 The Chromium Authors. All rights reserved.
|
| +// Use of this source code is governed by a BSD-style license that can be
|
| +// found in the LICENSE file.
|
| +
|
| +#import "ios/chrome/app/deferred_initialization_runner.h"
|
| +
|
| +#include "base/logging.h"
|
| +#include "base/mac/scoped_nsobject.h"
|
| +
|
| +// An object encapsulating the deferred execution of a block of initialization
|
| +// code.
|
| +@interface DeferredInitializationBlock : NSObject {
|
| + // A string to reference the initialization block.
|
| + base::scoped_nsobject<NSString> _name;
|
| + // A block of code to execute.
|
| + base::scoped_nsprotocol<ProceduralBlock> _runBlock;
|
| +}
|
| +
|
| +// Designated initializer.
|
| +- (id)initWithName:(NSString*)name block:(ProceduralBlock)block;
|
| +
|
| +// Dispatches the deferred execution the block after |delaySeconds|.
|
| +- (void)dispatch:(NSTimeInterval)delaySeconds;
|
| +
|
| +// Executes the deferred block now.
|
| +- (void)runSynchronously;
|
| +
|
| +// Cancels the block's execution.
|
| +- (void)cancel;
|
| +@end
|
| +
|
| +@implementation DeferredInitializationBlock
|
| +
|
| +// Overrides default designated initializer.
|
| +- (id)init {
|
| + NOTREACHED();
|
| + return nil;
|
| +}
|
| +
|
| +- (id)initWithName:(NSString*)name block:(ProceduralBlock)block {
|
| + DCHECK(block);
|
| + self = [super init];
|
| + if (self) {
|
| + _name.reset([name copy]);
|
| + _runBlock.reset([block copy]);
|
| + }
|
| + 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 {
|
| + ProceduralBlock deferredBlock = _runBlock.get();
|
| + if (!deferredBlock)
|
| + return;
|
| + deferredBlock();
|
| + [[DeferredInitializationRunner sharedInstance] cancelBlockNamed:_name];
|
| +}
|
| +
|
| +- (void)cancel {
|
| + _runBlock.reset();
|
| +}
|
| +
|
| +@end
|
| +
|
| +@implementation DeferredInitializationRunner {
|
| + base::scoped_nsobject<NSMutableDictionary> _runBlocks;
|
| +}
|
| +
|
| ++ (DeferredInitializationRunner*)sharedInstance {
|
| + static DeferredInitializationRunner* instance =
|
| + [[DeferredInitializationRunner alloc] init];
|
| + return instance;
|
| +}
|
| +
|
| +- (id)init {
|
| + self = [super init];
|
| + if (self)
|
| + _runBlocks.reset([[NSMutableDictionary dictionary] retain]);
|
| + return self;
|
| +}
|
| +
|
| +- (void)runBlockNamed:(NSString*)name
|
| + after:(NSTimeInterval)delaySeconds
|
| + block:(ProceduralBlock)block {
|
| + DCHECK(name);
|
| + // Safety check in case this function is called with a nanosecond or
|
| + // microsecond parameter by mistake.
|
| + DCHECK(delaySeconds < 3600.0);
|
| + // Cancels the previously scheduled block, if there is one, so this
|
| + // |name| block will not be run more than once.
|
| + [[_runBlocks objectForKey:name] cancel];
|
| + base::scoped_nsobject<DeferredInitializationBlock> deferredBlock(
|
| + [[DeferredInitializationBlock alloc] initWithName:name block:block]);
|
| + [_runBlocks setObject:deferredBlock forKey:name];
|
| + [deferredBlock dispatch:delaySeconds];
|
| +}
|
| +
|
| +- (void)runBlockIfNecessary:(NSString*)name {
|
| + [[_runBlocks objectForKey:name] runSynchronously];
|
| +}
|
| +
|
| +- (void)cancelBlockNamed:(NSString*)name {
|
| + DCHECK(name);
|
| + [[_runBlocks objectForKey:name] cancel];
|
| + [_runBlocks removeObjectForKey:name];
|
| +}
|
| +
|
| +@end
|
|
|