Permalink
Browse files

RCTUIManagerObserverCoordinator: new way to subscribe for granular no…

…tifications from UI Manager

Reviewed By: majak

Differential Revision: D4868591

fbshipit-source-id: 24a09ffa3e69dec5ce1f0a8715c7e4701d781996
  • Loading branch information...
shergin authored and facebook-github-bot committed May 8, 2017
1 parent 2a98432 commit 712b1dd20ab0de73594696103b73c461c2c97076
@@ -11,6 +11,7 @@
#import <React/RCTEventDispatcher.h>
#import <React/RCTEventEmitter.h>
#import <React/RCTUIManager.h>
#import <React/RCTUIManagerObserverCoordinator.h>
#import "RCTValueAnimatedNode.h"
@@ -28,7 +28,7 @@ - (void)invalidate
{
[_nodesManager stopAnimationLoop];
[self.bridge.eventDispatcher removeDispatchObserver:self];
[self.bridge.uiManager removeUIManagerObserver:self];
[self.bridge.uiManager.observerCoordinator removeObserver:self];
}
- (dispatch_queue_t)methodQueue
@@ -48,7 +48,7 @@ - (void)setBridge:(RCTBridge *)bridge
_preOperations = [NSMutableArray new];
[bridge.eventDispatcher addDispatchObserver:self];
[bridge.uiManager addUIManagerObserver:self];
[bridge.uiManager.observerCoordinator addObserver:self];
}
#pragma mark -- API
@@ -196,6 +196,8 @@ - (void)addPreOperationBlock:(AnimatedOperation)operation
[_preOperations addObject:operation];
}
#pragma mark - RCTUIManagerObserver
- (void)uiManagerWillFlushUIBlocks:(RCTUIManager *)uiManager
{
if (_preOperations.count == 0 && _operations.count == 0) {
@@ -59,24 +59,7 @@ RCT_EXTERN NSString *const RCTUIManagerDidRemoveRootViewNotification;
*/
RCT_EXTERN NSString *const RCTUIManagerRootViewKey;
@class RCTUIManager;
/**
* Allows to hook into UIManager internals. This can be used to execute code at
* specific points during the view updating process.
*/
@protocol RCTUIManagerObserver <NSObject>
/**
* Called before flushing UI blocks at the end of a batch. Note that this won't
* get called for partial batches when using `unsafeFlushUIChangesBeforeBatchEnds`.
* This is called from the UIManager queue. Can be used to add UI operations in that batch.
*/
- (void)uiManagerWillFlushUIBlocks:(RCTUIManager *)manager;
@end
@protocol RCTScrollableProtocol;
@class RCTUIManagerObserverCoordinator;
/**
* The RCTUIManager is the module responsible for updating the view hierarchy.
@@ -139,17 +122,6 @@ RCT_EXTERN NSString *const RCTUIManagerRootViewKey;
*/
- (void)prependUIBlock:(RCTViewManagerUIBlock)block;
/**
* Add a UIManagerObserver. See the RCTUIManagerObserver protocol for more info. This
* method can be called safely from any queue.
*/
- (void)addUIManagerObserver:(id<RCTUIManagerObserver>)observer;
/**
* Remove a UIManagerObserver. This method can be called safely from any queue.
*/
- (void)removeUIManagerObserver:(id<RCTUIManagerObserver>)observer;
/**
* Used by native animated module to bypass the process of updating the values through the shadow
* view hierarchy. This method will directly update native views, which means that updates for
@@ -192,6 +164,12 @@ RCT_EXTERN NSString *const RCTUIManagerRootViewKey;
*/
- (void)setNeedsLayout;
/**
* Dedicated object for subscribing for UIManager events.
* See `RCTUIManagerObserver` protocol for more details.
*/
@property (atomic, retain, readonly) RCTUIManagerObserverCoordinator *observerCoordinator;
@end
@interface RCTUIManager (Deprecated)
@@ -33,6 +33,7 @@
#import "RCTScrollableProtocol.h"
#import "RCTShadowView.h"
#import "RCTUtils.h"
#import "RCTUIManagerObserverCoordinator.h"
#import "RCTView.h"
#import "RCTViewManager.h"
#import "UIView+React.h"
@@ -225,7 +226,6 @@ @implementation RCTUIManager
NSDictionary *_componentDataByName;
NSMutableSet<id<RCTComponent>> *_bridgeTransactionListeners;
NSMutableSet<id<RCTUIManagerObserver>> *_uiManagerObservers;
}
@synthesize bridge = _bridge;
@@ -306,7 +306,7 @@ - (void)setBridge:(RCTBridge *)bridge
_rootViewTags = [NSMutableSet new];
_bridgeTransactionListeners = [NSMutableSet new];
_uiManagerObservers = [NSMutableSet new];
_observerCoordinator = [RCTUIManagerObserverCoordinator new];
_viewsToBeDeleted = [NSMutableSet new];
@@ -723,20 +723,6 @@ - (void)_amendPendingUIBlocksWithStylePropagationUpdateForShadowView:(RCTShadowV
}
}
- (void)addUIManagerObserver:(id<RCTUIManagerObserver>)observer
{
dispatch_async(RCTGetUIManagerQueue(), ^{
[self->_uiManagerObservers addObject:observer];
});
}
- (void)removeUIManagerObserver:(id<RCTUIManagerObserver>)observer
{
dispatch_async(RCTGetUIManagerQueue(), ^{
[self->_uiManagerObservers removeObject:observer];
});
}
/**
* A method to be called from JS, which takes a container ID and then releases
* all subviews for that container upon receipt.
@@ -1159,10 +1145,19 @@ - (void)_layoutAndMount
[self addUIBlock:uiBlock];
}
[_observerCoordinator uiManagerWillPerformLayout:self];
// Perform layout
for (NSNumber *reactTag in _rootViewTags) {
RCTRootShadowView *rootView = (RCTRootShadowView *)_shadowViewRegistry[reactTag];
[self addUIBlock:[self uiBlockWithLayoutUpdateForRootView:rootView]];
}
[_observerCoordinator uiManagerDidPerformLayout:self];
// Properies propagation
for (NSNumber *reactTag in _rootViewTags) {
RCTRootShadowView *rootView = (RCTRootShadowView *)_shadowViewRegistry[reactTag];
[self _amendPendingUIBlocksWithStylePropagationUpdateForShadowView:rootView];
}
@@ -1175,9 +1170,7 @@ - (void)_layoutAndMount
}
}];
for (id<RCTUIManagerObserver> observer in _uiManagerObservers) {
[observer uiManagerWillFlushUIBlocks:self];
}
[_observerCoordinator uiManagerWillFlushUIBlocks:self];
[self flushUIBlocks];
}
@@ -0,0 +1,67 @@
/**
* Copyright (c) 2015-present, Facebook, Inc.
* All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
* LICENSE file in the root directory of this source tree. An additional grant
* of patent rights can be found in the PATENTS file in the same directory.
*/
#import <UIKit/UIKit.h>
#import <React/RCTViewManager.h>
/**
* Allows to hook into UIManager internals. This can be used to execute code at
* specific points during the view updating process.
* All observer handler is called on UIManager queue.
*/
@protocol RCTUIManagerObserver <NSObject>
@optional
/**
* Called just before the UIManager layout views.
* It allows performing some operation for components which contain custom
* layout logic right before regular Yoga based layout. So, for instance,
* some components which have own React-independent state can compute and cache
* own intrinsic content size (which will be used by Yoga) at this point.
*/
- (void)uiManagerWillPerformLayout:(RCTUIManager *)manager;
/**
* Called just after the UIManager layout views.
* It allows performing custom layout logic right after regular Yoga based layout.
* So, for instance, this can be used for computing final layout for a component,
* since it has its final frame set by Yoga at this point.
*/
- (void)uiManagerDidPerformLayout:(RCTUIManager *)manager;
/**
* Called before flushing UI blocks at the end of a batch. Note that this won't
* get called for partial batches when using `unsafeFlushUIChangesBeforeBatchEnds`.
* This is called from the UIManager queue. Can be used to add UI operations in that batch.
*/
- (void)uiManagerWillFlushUIBlocks:(RCTUIManager *)manager;
@end
/**
* Simple helper which take care of RCTUIManager's observers.
*/
@interface RCTUIManagerObserverCoordinator : NSObject <RCTUIManagerObserver>
/**
* Add a UIManagerObserver. See the `RCTUIManagerObserver` protocol for more info.
* References to observers are held weakly.
* This method can be called safely from any queue.
*/
- (void)addObserver:(id<RCTUIManagerObserver>)observer;
/**
* Remove a `UIManagerObserver`.
* This method can be called safely from any queue.
*/
- (void)removeObserver:(id<RCTUIManagerObserver>)observer;
@end
@@ -0,0 +1,70 @@
/**
* Copyright (c) 2015-present, Facebook, Inc.
* All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
* LICENSE file in the root directory of this source tree. An additional grant
* of patent rights can be found in the PATENTS file in the same directory.
*/
#import "RCTUIManagerObserverCoordinator.h"
#import "RCTUIManager.h"
@implementation RCTUIManagerObserverCoordinator {
NSHashTable<id<RCTUIManagerObserver>> *_observers;
}
- (instancetype)init
{
if (self = [super init]) {
_observers = [[NSHashTable alloc] initWithOptions:NSHashTableWeakMemory capacity:0];
}
return self;
}
- (void)addObserver:(id<RCTUIManagerObserver>)observer
{
dispatch_async(RCTGetUIManagerQueue(), ^{
[self->_observers addObject:observer];
});
}
- (void)removeObserver:(id<RCTUIManagerObserver>)observer
{
dispatch_async(RCTGetUIManagerQueue(), ^{
[self->_observers removeObject:observer];
});
}
#pragma mark - RCTUIManagerObserver
- (void)uiManagerWillPerformLayout:(RCTUIManager *)manager
{
for (id<RCTUIManagerObserver> observer in _observers) {
if ([observer respondsToSelector:@selector(uiManagerWillPerformLayout:)]) {
[observer uiManagerWillPerformLayout:manager];
}
}
}
- (void)uiManagerDidPerformLayout:(RCTUIManager *)manager
{
for (id<RCTUIManagerObserver> observer in _observers) {
if ([observer respondsToSelector:@selector(uiManagerDidPerformLayout:)]) {
[observer uiManagerDidPerformLayout:manager];
}
}
}
- (void)uiManagerWillFlushUIBlocks:(RCTUIManager *)manager
{
for (id<RCTUIManagerObserver> observer in _observers) {
if ([observer respondsToSelector:@selector(uiManagerWillFlushUIBlocks:)]) {
[observer uiManagerWillFlushUIBlocks:manager];
}
}
}
@end
Oops, something went wrong.

0 comments on commit 712b1dd

Please sign in to comment.