Skip to content

Commit

Permalink
Merge branch 'master' into MSAccessRangeControllerWithoutViewNeeded
Browse files Browse the repository at this point in the history
  • Loading branch information
Adlai-Holler committed Sep 18, 2018
2 parents 5c983e6 + 1452b31 commit fd7ecae
Show file tree
Hide file tree
Showing 9 changed files with 161 additions and 71 deletions.
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,8 @@
- Improve TextNode2 by skipping an unneeded copy during measurement. [Adlai Holler](https://github.com/Adlai-Holler)
- Improve locking around clearContents [Michael Schneider](https://github.com/maicki)
- Unlock before cleanup and calling out to subclass hooks for animated images. [Michael Schneider](https://github.com/maicki) [#1087](https://github.com/TextureGroup/Texture/pull/1087)
- [ASDisplayNode] Fix interface state update for layer backed nodes when layer thrashes (interface coaleascing case).[Max Wang](https://github.com/wsdwsd0829). [#1111](https://github.com/TextureGroup/Texture/pull/1111)
- [ASPINRemoteImageManager] Add a new API for setting a preconfigured PINRemoteImageManager. [Ernest Ma](https://github.com/ernestmama) [#1124](https://github.com/TextureGroup/Texture/pull/1124)
- Remove necessity to use view to access rangeController in ASTableNode, ASCollectionNode. [Michael Schneider](https://github.com/maicki)

## 2.7
Expand Down
6 changes: 6 additions & 0 deletions Source/ASDisplayNode.h
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,10 @@ NS_ASSUME_NONNULL_BEGIN

#define ASDisplayNodeLoggingEnabled 0

#ifndef AS_MAX_INTERFACE_STATE_DELEGATES
#define AS_MAX_INTERFACE_STATE_DELEGATES 4
#endif

@class ASDisplayNode;
@protocol ASContextTransitioning;

Expand Down Expand Up @@ -258,6 +262,8 @@ AS_EXTERN NSInteger const ASDefaultDrawingPriority;
* @abstract Adds a delegate to receive notifications on interfaceState changes.
*
* @warning This must be called from the main thread.
* There is a hard limit on the number of delegates a node can have; see
* AS_MAX_INTERFACE_STATE_DELEGATES above.
*
* @see ASInterfaceState
*/
Expand Down
114 changes: 78 additions & 36 deletions Source/ASDisplayNode.mm
Original file line number Diff line number Diff line change
Expand Up @@ -452,17 +452,6 @@ - (void)dealloc

#pragma mark - Loading

#define ASDisplayNodeCallInterfaceStateDelegates(method) \
__instanceLock__.lock(); \
NSHashTable *delegates = _copiedInterfaceStateDelegates; \
if (!delegates) { \
delegates = _copiedInterfaceStateDelegates = [_interfaceStateDelegates copy]; \
} \
__instanceLock__.unlock(); \
for (id <ASInterfaceStateDelegate> delegate in delegates) { \
[delegate method]; \
}

- (BOOL)_locked_shouldLoadViewOrLayer
{
ASAssertLocked(__instanceLock__);
Expand Down Expand Up @@ -568,14 +557,15 @@ - (void)_didLoad
[self didLoad];

__instanceLock__.lock();
NSArray *onDidLoadBlocks = [_onDidLoadBlocks copy];
_onDidLoadBlocks = nil;
let onDidLoadBlocks = ASTransferStrong(_onDidLoadBlocks);
__instanceLock__.unlock();

for (ASDisplayNodeDidLoadBlock block in onDidLoadBlocks) {
block(self);
}
ASDisplayNodeCallInterfaceStateDelegates(nodeDidLoad);
[self enumerateInterfaceStateDelegates:^(id<ASInterfaceStateDelegate> del) {
[del nodeDidLoad];
}];
}

- (void)didLoad
Expand Down Expand Up @@ -1280,7 +1270,9 @@ - (void)layout
ASDisplayNodeAssertMainThread();
ASAssertUnlocked(__instanceLock__);
ASDisplayNodeAssertTrue(self.isNodeLoaded);
ASDisplayNodeCallInterfaceStateDelegates(nodeDidLayout);
[self enumerateInterfaceStateDelegates:^(id<ASInterfaceStateDelegate> del) {
[del nodeDidLayout];
}];
}

#pragma mark Layout Transition
Expand Down Expand Up @@ -1503,7 +1495,9 @@ - (void)_pendingNodeDidDisplay:(ASDisplayNode *)node
if (_pendingDisplayNodes.isEmpty) {

[self hierarchyDisplayDidFinish];
ASDisplayNodeCallInterfaceStateDelegates(hierarchyDisplayDidFinish);
[self enumerateInterfaceStateDelegates:^(id<ASInterfaceStateDelegate> delegate) {
[delegate hierarchyDisplayDidFinish];
}];

BOOL placeholderShouldPersist = [self placeholderShouldPersist];

Expand Down Expand Up @@ -2945,6 +2939,15 @@ - (void)willEnterHierarchy

if (![self supportsRangeManagedInterfaceState]) {
self.interfaceState = ASInterfaceStateInHierarchy;
} else if (ASCATransactionQueue.sharedQueue.isEnabled) {
__instanceLock__.lock();
ASInterfaceState state = _preExitingInterfaceState;
_preExitingInterfaceState = ASInterfaceStateNone;
__instanceLock__.unlock();
// Layer thrash happened, revert to before exiting.
if (state != ASInterfaceStateNone) {
self.interfaceState = state;
}
}
}

Expand Down Expand Up @@ -2983,6 +2986,8 @@ - (void)didExitHierarchy
unsigned isStillInHierarchy = _flags.isInHierarchy;
BOOL isVisible = ASInterfaceStateIncludesVisible(_pendingInterfaceState);
ASInterfaceState newState = (_pendingInterfaceState & ~ASInterfaceStateVisible);
// layer may be thrashed, we need to remember the state so we can reset if it enters in same runloop later.
_preExitingInterfaceState = _pendingInterfaceState;
__instanceLock__.unlock();
if (!isStillInHierarchy && isVisible) {
#if ENABLE_NEW_EXIT_HIERARCHY_BEHAVIOR
Expand Down Expand Up @@ -3100,6 +3105,7 @@ - (void)applyPendingInterfaceState:(ASInterfaceState)newPendingState
return;
}
_interfaceState = newState;
_preExitingInterfaceState = ASInterfaceStateNone;
}

// It should never be possible for a node to be visible but not be allowed / expected to display.
Expand Down Expand Up @@ -3216,12 +3222,9 @@ - (void)interfaceStateDidChange:(ASInterfaceState)newState fromState:(ASInterfac
// Subclass hook
ASAssertUnlocked(__instanceLock__);
ASDisplayNodeAssertMainThread();
__instanceLock__.lock();
NSHashTable *delegates = [_interfaceStateDelegates copy];
__instanceLock__.unlock();
for (id <ASInterfaceStateDelegate> delegate in delegates) {
[delegate interfaceStateDidChange:newState fromState:oldState];
}
[self enumerateInterfaceStateDelegates:^(id<ASInterfaceStateDelegate> del) {
[del interfaceStateDidChange:newState fromState:oldState];
}];
}

- (BOOL)shouldScheduleDisplayWithNewInterfaceState:(ASInterfaceState)newInterfaceState
Expand All @@ -3234,20 +3237,25 @@ - (BOOL)shouldScheduleDisplayWithNewInterfaceState:(ASInterfaceState)newInterfac
- (void)addInterfaceStateDelegate:(id <ASInterfaceStateDelegate>)interfaceStateDelegate
{
ASDN::MutexLocker l(__instanceLock__);
// Not a fan of lazy loading, but this method won't get called very often and avoiding
// the overhead of creating this is probably worth it.
if (_interfaceStateDelegates == nil) {
_interfaceStateDelegates = [NSHashTable weakObjectsHashTable];
_hasHadInterfaceStateDelegates = YES;
for (int i = 0; i < AS_MAX_INTERFACE_STATE_DELEGATES; i++) {
if (_interfaceStateDelegates[i] == nil) {
_interfaceStateDelegates[i] = interfaceStateDelegate;
return;
}
}
_copiedInterfaceStateDelegates = nil;
[_interfaceStateDelegates addObject:interfaceStateDelegate];
ASDisplayNodeFailAssert(@"Exceeded interface state delegate limit: %d", AS_MAX_INTERFACE_STATE_DELEGATES);
}

- (void)removeInterfaceStateDelegate:(id <ASInterfaceStateDelegate>)interfaceStateDelegate
{
ASDN::MutexLocker l(__instanceLock__);
_copiedInterfaceStateDelegates = nil;
[_interfaceStateDelegates removeObject:interfaceStateDelegate];
for (int i = 0; i < AS_MAX_INTERFACE_STATE_DELEGATES; i++) {
if (_interfaceStateDelegates[i] == interfaceStateDelegate) {
_interfaceStateDelegates[i] = nil;
break;
}
}
}

- (BOOL)isVisible
Expand All @@ -3261,7 +3269,9 @@ - (void)didEnterVisibleState
// subclass override
ASDisplayNodeAssertMainThread();
ASAssertUnlocked(__instanceLock__);
ASDisplayNodeCallInterfaceStateDelegates(didEnterVisibleState);
[self enumerateInterfaceStateDelegates:^(id<ASInterfaceStateDelegate> del) {
[del didEnterVisibleState];
}];
#if AS_ENABLE_TIPS
[ASTipsController.shared nodeDidAppear:self];
#endif
Expand All @@ -3272,7 +3282,9 @@ - (void)didExitVisibleState
// subclass override
ASDisplayNodeAssertMainThread();
ASAssertUnlocked(__instanceLock__);
ASDisplayNodeCallInterfaceStateDelegates(didExitVisibleState);
[self enumerateInterfaceStateDelegates:^(id<ASInterfaceStateDelegate> del) {
[del didExitVisibleState];
}];
}

- (BOOL)isInDisplayState
Expand All @@ -3286,15 +3298,19 @@ - (void)didEnterDisplayState
// subclass override
ASDisplayNodeAssertMainThread();
ASAssertUnlocked(__instanceLock__);
ASDisplayNodeCallInterfaceStateDelegates(didEnterDisplayState);
[self enumerateInterfaceStateDelegates:^(id<ASInterfaceStateDelegate> del) {
[del didEnterDisplayState];
}];
}

- (void)didExitDisplayState
{
// subclass override
ASDisplayNodeAssertMainThread();
ASAssertUnlocked(__instanceLock__);
ASDisplayNodeCallInterfaceStateDelegates(didExitDisplayState);
[self enumerateInterfaceStateDelegates:^(id<ASInterfaceStateDelegate> del) {
[del didExitDisplayState];
}];
}

- (BOOL)isInPreloadState
Expand Down Expand Up @@ -3344,14 +3360,18 @@ - (void)didEnterPreloadState
if (self.automaticallyManagesSubnodes) {
[self layoutIfNeeded];
}
ASDisplayNodeCallInterfaceStateDelegates(didEnterPreloadState);
[self enumerateInterfaceStateDelegates:^(id<ASInterfaceStateDelegate> del) {
[del didEnterPreloadState];
}];
}

- (void)didExitPreloadState
{
ASDisplayNodeAssertMainThread();
ASAssertUnlocked(__instanceLock__);
ASDisplayNodeCallInterfaceStateDelegates(didExitPreloadState);
[self enumerateInterfaceStateDelegates:^(id<ASInterfaceStateDelegate> del) {
[del didExitPreloadState];
}];
}

- (void)clearContents
Expand All @@ -3378,7 +3398,29 @@ - (void)recursivelyClearContents
});
}

- (void)enumerateInterfaceStateDelegates:(void (NS_NOESCAPE ^)(id<ASInterfaceStateDelegate>))block
{
ASAssertUnlocked(__instanceLock__);

id dels[AS_MAX_INTERFACE_STATE_DELEGATES];
int count = 0;
{
ASLockScopeSelf();
// Fast path for non-delegating nodes.
if (!_hasHadInterfaceStateDelegates) {
return;
}

for (int i = 0; i < AS_MAX_INTERFACE_STATE_DELEGATES; i++) {
if ((dels[count] = _interfaceStateDelegates[i])) {
count++;
}
}
}
for (int i = 0; i < count; i++) {
block(dels[i]);
}
}

#pragma mark - Gesture Recognizing

Expand Down
3 changes: 1 addition & 2 deletions Source/ASEditableTextNode.h
Original file line number Diff line number Diff line change
Expand Up @@ -192,13 +192,12 @@ NS_ASSUME_NONNULL_BEGIN
- (void)editableTextNodeDidUpdateText:(ASEditableTextNode *)editableTextNode;

/**
@abstract Indicates to the delegate that teh text node has finished editing.
@abstract Indicates to the delegate that the text node has finished editing.
@param editableTextNode An editable text node.
@discussion The invocation of this method coincides with the keyboard animating to become hidden.
*/
- (void)editableTextNodeDidFinishEditing:(ASEditableTextNode *)editableTextNode;


@end

NS_ASSUME_NONNULL_END
17 changes: 16 additions & 1 deletion Source/Base/ASBaseDefines.h
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
// Licensed under Apache 2.0: http://www.apache.org/licenses/LICENSE-2.0
//

#import <Foundation/NSObjCRuntime.h>
#import <Foundation/Foundation.h>

#define AS_EXTERN FOUNDATION_EXTERN
#define unowned __unsafe_unretained
Expand Down Expand Up @@ -229,3 +229,18 @@
} \
__result; \
})

/**
* Capture-and-clear a strong reference without the intervening retain/release pair.
*
* E.g. let localVar = ASTransferStrong(_myIvar);
* Post-condition: localVar has the strong value from _myIvar and _myIvar is nil.
* No retain/release is emitted when the optimizer is on.
*/
#define ASTransferStrong(lvalue) ({ \
CFTypeRef *__rawPtr = (CFTypeRef *)(void *)(&(lvalue)); \
CFTypeRef __cfValue = *__rawPtr; \
*__rawPtr = NULL; \
__typeof(lvalue) __result = (__bridge_transfer __typeof(lvalue))__cfValue; \
__result; \
})
11 changes: 10 additions & 1 deletion Source/Details/ASPINRemoteImageDownloader.h
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,6 @@ NS_ASSUME_NONNULL_BEGIN
* This is the default downloader used by network backed image nodes if PINRemoteImage and PINCache are
* available. It uses PINRemoteImage's features to provide caching and progressive image downloads.
*/
@property (class, readonly) ASPINRemoteImageDownloader *sharedDownloader;
+ (ASPINRemoteImageDownloader *)sharedDownloader NS_RETURNS_RETAINED;


Expand All @@ -40,6 +39,16 @@ NS_ASSUME_NONNULL_BEGIN
*/
+ (void)setSharedImageManagerWithConfiguration:(nullable NSURLSessionConfiguration *)configuration;

/**
* Sets a custom preconfigured PINRemoteImageManager that will be used by @c ASNetworkImageNodes and @c ASMultiplexImageNodes
* while loading images off the network. This must be specified early in the application lifecycle before
* `sharedDownloader` is accessed. If nil is passed in as the PINRemoteImageManager, it will create
* a default image manager with a nil session configuration.
*
* @param PINRemoteImageManager The preconfigured remote image manager that will be used by `sharedDownloader`
*/
+ (void)setSharedPreconfiguredRemoteImageManager:(nullable PINRemoteImageManager *)preconfiguredPINRemoteImageManager;

/**
* The shared instance of a @c PINRemoteImageManager used by all @c ASPINRemoteImageDownloaders
*
Expand Down
Loading

0 comments on commit fd7ecae

Please sign in to comment.