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..46ce2c52eebe3547673ef7b2d3ba9de56f30234b 100644 |
--- a/ios/chrome/app/deferred_initialization_runner.mm |
+++ b/ios/chrome/app/deferred_initialization_runner.mm |
@@ -6,6 +6,7 @@ |
#include <stdint.h> |
+#import "base/ios/weak_nsobject.h" |
#include "base/logging.h" |
#include "base/mac/scoped_nsobject.h" |
@@ -18,28 +19,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 +64,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 +78,87 @@ |
@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); |
jif
2016/09/26 09:12:47
I'm afraid of |enqueueBlockNamed:| being called wh
gambard
2016/09/26 13:42:55
Done.
|
+ [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 { |
+ _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 +176,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]; |
} |