Skip to content
This repository was archived by the owner on Feb 2, 2023. It is now read-only.

Commit ae29cd2

Browse files
committed
Merge remote-tracking branch 'facebook/master'
2 parents 970f0e2 + 4cfe3f7 commit ae29cd2

73 files changed

Lines changed: 2609 additions & 322 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

AsyncDisplayKit.xcodeproj/project.pbxproj

Lines changed: 76 additions & 18 deletions
Large diffs are not rendered by default.

AsyncDisplayKit/ASCollectionNode.mm

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
#import "ASCollectionInternal.h"
1111
#import "ASCollectionViewLayoutFacilitatorProtocol.h"
1212
#import "ASDisplayNode+Subclasses.h"
13+
#import "ASEnvironmentInternal.h"
1314
#import "ASRangeControllerUpdateRangeProtocol+Beta.h"
1415
#include <vector>
1516

@@ -53,6 +54,9 @@ - (void)setTuningParameters:(ASRangeTuningParameters)tuningParameters forRangeTy
5354
#endif
5455

5556
@interface ASCollectionNode ()
57+
{
58+
ASDN::RecursiveMutex _environmentStateLock;
59+
}
5660
@property (nonatomic) _ASCollectionPendingState *pendingState;
5761
@end
5862

@@ -244,4 +248,6 @@ - (void)reloadDataImmediately
244248
[self.view reloadDataImmediately];
245249
}
246250

251+
ASEnvironmentCollectionTableSetEnvironmentState(_environmentStateLock)
252+
247253
@end

AsyncDisplayKit/ASCollectionView.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -342,7 +342,7 @@ NS_ASSUME_NONNULL_BEGIN
342342
* This is a node-based UICollectionViewDataSource.
343343
*/
344344
#define ASCollectionViewDataSource ASCollectionDataSource
345-
@protocol ASCollectionDataSource <ASCommonCollectionViewDataSource, NSObject>
345+
@protocol ASCollectionDataSource <ASCommonCollectionViewDataSource>
346346

347347
@optional
348348

AsyncDisplayKit/ASCollectionView.mm

Lines changed: 17 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -91,7 +91,7 @@ - (instancetype)init
9191
#pragma mark -
9292
#pragma mark ASCollectionView.
9393

94-
@interface ASCollectionView () <ASRangeControllerDataSource, ASRangeControllerDelegate, ASDataControllerSource, ASCellNodeLayoutDelegate, ASDelegateProxyInterceptor, ASBatchFetchingScrollView> {
94+
@interface ASCollectionView () <ASRangeControllerDataSource, ASRangeControllerDelegate, ASDataControllerSource, ASCellNodeLayoutDelegate, ASDelegateProxyInterceptor, ASBatchFetchingScrollView, ASDataControllerEnvironmentDelegate> {
9595
ASCollectionViewProxy *_proxyDataSource;
9696
ASCollectionViewProxy *_proxyDelegate;
9797

@@ -225,6 +225,7 @@ - (instancetype)_initWithFrame:(CGRect)frame collectionViewLayout:(UICollectionV
225225
_dataController = [[ASCollectionDataController alloc] initWithAsyncDataFetching:NO];
226226
_dataController.delegate = _rangeController;
227227
_dataController.dataSource = self;
228+
_dataController.environmentDelegate = self;
228229

229230
_batchContext = [[ASBatchContext alloc] init];
230231

@@ -343,10 +344,10 @@ - (void)setAsyncDataSource:(id<ASCollectionViewDataSource>)asyncDataSource
343344
{
344345
// Note: It's common to check if the value hasn't changed and short-circuit but we aren't doing that here to handle
345346
// the (common) case of nilling the asyncDataSource in the ViewController's dealloc. In this case our _asyncDataSource
346-
// will return as nil (ARC magic) even though the _proxyDataSource still exists. It's really important to nil out
347-
// super.dataSource in this case because calls to ASCollectionViewProxy will start failing and cause crashes.
348-
349-
super.dataSource = nil;
347+
// will return as nil (ARC magic) even though the _proxyDataSource still exists. It's really important to hold a strong
348+
// reference to the old dataSource in this case because calls to ASCollectionViewProxy will start failing and cause crashes.
349+
NS_VALID_UNTIL_END_OF_SCOPE id oldDataSource = super.dataSource;
350+
350351
if (asyncDataSource == nil) {
351352
_asyncDataSource = nil;
352353
_proxyDataSource = _isDeallocating ? nil : [[ASCollectionViewProxy alloc] initWithTarget:nil interceptor:self];
@@ -375,13 +376,9 @@ - (void)setAsyncDelegate:(id<ASCollectionViewDelegate>)asyncDelegate
375376
{
376377
// Note: It's common to check if the value hasn't changed and short-circuit but we aren't doing that here to handle
377378
// the (common) case of nilling the asyncDelegate in the ViewController's dealloc. In this case our _asyncDelegate
378-
// will return as nil (ARC magic) even though the _proxyDelegate still exists. It's really important to nil out
379-
// super.delegate in this case because calls to ASCollectionViewProxy will start failing and cause crashes.
380-
381-
// Order is important here, the asyncDelegate must be callable while nilling super.delegate to avoid random crashes
382-
// in UIScrollViewAccessibility.
383-
384-
super.delegate = nil;
379+
// will return as nil (ARC magic) even though the _proxyDataSource still exists. It's really important to hold a strong
380+
// reference to the old delegate in this case because calls to ASCollectionViewProxy will start failing and cause crashes.
381+
NS_VALID_UNTIL_END_OF_SCOPE id oldDelegate = super.delegate;
385382

386383
if (asyncDelegate == nil) {
387384
_asyncDelegate = nil;
@@ -921,6 +918,14 @@ - (void)dataControllerUnlockDataSource
921918
}
922919
}
923920

921+
- (id<ASEnvironment>)dataControllerEnvironment
922+
{
923+
if (self.collectionNode) {
924+
return self.collectionNode;
925+
}
926+
return self.strongCollectionNode;
927+
}
928+
924929
#pragma mark - ASCollectionViewDataControllerSource Supplementary view support
925930

926931
- (ASCellNode *)dataController:(ASCollectionDataController *)dataController supplementaryNodeOfKind:(NSString *)kind atIndexPath:(NSIndexPath *)indexPath

AsyncDisplayKit/ASDisplayNode.mm

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
#import "_ASCoreAnimationExtras.h"
2323
#import "ASDisplayNodeLayoutContext.h"
2424
#import "ASDisplayNodeExtras.h"
25+
#import "ASTraitCollection.h"
2526
#import "ASEqualityHelpers.h"
2627
#import "ASRunLoopQueue.h"
2728
#import "ASEnvironmentInternal.h"
@@ -2710,9 +2711,24 @@ - (BOOL)supportsUpwardPropagation
27102711
return ASEnvironmentStatePropagationEnabled();
27112712
}
27122713

2714+
- (BOOL)supportsTraitsCollectionPropagation
2715+
{
2716+
return ASEnvironmentStateTraitCollectionPropagationEnabled();
2717+
}
2718+
2719+
- (ASEnvironmentTraitCollection)environmentTraitCollection
2720+
{
2721+
return _environmentState.traitCollection;
2722+
}
2723+
27132724
ASEnvironmentLayoutOptionsForwarding
27142725
ASEnvironmentLayoutExtensibilityForwarding
27152726

2727+
- (ASTraitCollection *)asyncTraitCollection
2728+
{
2729+
ASDN::MutexLocker l(_propertyLock);
2730+
return [ASTraitCollection traitCollectionWithASEnvironmentTraitCollection:_environmentState.traitCollection];
2731+
}
27162732

27172733
#if TARGET_OS_TV
27182734
#pragma mark - UIFocusEnvironment Protocol (tvOS)

AsyncDisplayKit/ASMultiplexImageNode.h

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -117,13 +117,20 @@ typedef NS_ENUM(NSUInteger, ASMultiplexImageNodeErrorCode) {
117117
*/
118118
@property (nullable, nonatomic, readonly) ASImageIdentifier displayedImageIdentifier;
119119

120+
/**
121+
* @abstract If the downloader implements progressive image rendering and this value is YES progressive renders of the
122+
* image will be displayed as the image downloads. Regardless of this properties value, progress renders will
123+
* only occur when the node is visible. Defaults to YES.
124+
*/
125+
@property (nonatomic, assign, readwrite) BOOL shouldRenderProgressImages;
126+
120127
#if TARGET_OS_IOS
121128
/**
122129
* @abstract The image manager that this image node should use when requesting images from the Photos framework. If this is `nil` (the default), then `PHImageManager.defaultManager` is used.
123130
124131
* @see `+[NSURL URLWithAssetLocalIdentifier:targetSize:contentMode:options:]` below.
125132
*/
126-
@property (nonatomic, strong) PHImageManager *imageManager;
133+
@property (nullable, nonatomic, strong) PHImageManager *imageManager;
127134
#endif
128135
@end
129136

AsyncDisplayKit/ASMultiplexImageNode.mm

Lines changed: 59 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,10 @@ @interface ASMultiplexImageNode ()
8585
ASDN::RecursiveMutex _downloadIdentifierLock;
8686
id _downloadIdentifier;
8787

88+
// Properties
89+
ASDN::RecursiveMutex _propertyLock;
90+
BOOL _shouldRenderProgressImages;
91+
8892
//set on init only
8993
BOOL _downloaderSupportsNewProtocol;
9094
BOOL _downloaderImplementsSetProgress;
@@ -186,6 +190,8 @@ - (instancetype)initWithCache:(id<ASImageCacheProtocol>)cache downloader:(id<ASI
186190
_cacheSupportsNewProtocol = [cache respondsToSelector:@selector(cachedImageWithURL:callbackQueue:completion:)];
187191
_cacheSupportsClearing = [cache respondsToSelector:@selector(clearFetchedImageFromCacheWithURL:)];
188192

193+
_shouldRenderProgressImages = YES;
194+
189195
self.shouldBypassEnsureDisplay = YES;
190196

191197
return self;
@@ -339,6 +345,27 @@ - (void)setDataSource:(id <ASMultiplexImageNodeDataSource>)dataSource
339345
#endif
340346
}
341347

348+
349+
- (void)setShouldRenderProgressImages:(BOOL)shouldRenderProgressImages
350+
{
351+
ASDN::MutexLocker l(_propertyLock);
352+
if (shouldRenderProgressImages == _shouldRenderProgressImages) {
353+
return;
354+
}
355+
356+
_shouldRenderProgressImages = shouldRenderProgressImages;
357+
358+
359+
ASDN::MutexUnlocker u(_propertyLock);
360+
[self _updateProgressImageBlockOnDownloaderIfNeeded];
361+
}
362+
363+
- (BOOL)shouldRenderProgressImages
364+
{
365+
ASDN::MutexLocker l(_propertyLock);
366+
return _shouldRenderProgressImages;
367+
}
368+
342369
#pragma mark -
343370

344371
#pragma mark -
@@ -436,8 +463,12 @@ - (UIImage *)_bestImmediatelyAvailableImageFromDataSource:(id *)imageIdentifierO
436463
}
437464

438465
// Grab the best available image from the data source.
466+
UIImage *existingImage = self.image;
439467
for (id imageIdentifier in _imageIdentifiers) {
440-
UIImage *image = [_dataSource multiplexImageNode:self imageForImageIdentifier:imageIdentifier];
468+
// If this image is already loaded, don't request it from the data source again because
469+
// the data source may generate a new instance of UIImage that returns NO for isEqual:
470+
// and we'll end up in an infinite loading loop.
471+
UIImage *image = ASObjectIsEqual(imageIdentifier, _loadedImageIdentifier) ? existingImage : [_dataSource multiplexImageNode:self imageForImageIdentifier:imageIdentifier];
441472
if (image) {
442473
if (imageIdentifierOut) {
443474
*imageIdentifierOut = imageIdentifier;
@@ -458,32 +489,34 @@ - (UIImage *)_bestImmediatelyAvailableImageFromDataSource:(id *)imageIdentifierO
458489
*/
459490
- (void)_updateProgressImageBlockOnDownloaderIfNeeded
460491
{
461-
// Read our interface state before locking so that we don't lock super while holding our lock.
462-
ASInterfaceState interfaceState = self.interfaceState;
463-
ASDN::MutexLocker l(_downloadIdentifierLock);
464-
465-
if (!_downloaderImplementsSetProgress || _downloadIdentifier == nil) {
492+
BOOL shouldRenderProgressImages = self.shouldRenderProgressImages;
493+
494+
// Read our interface state before locking so that we don't lock super while holding our lock.
495+
ASInterfaceState interfaceState = self.interfaceState;
496+
ASDN::MutexLocker l(_downloadIdentifierLock);
497+
498+
if (!_downloaderImplementsSetProgress || _downloadIdentifier == nil) {
499+
return;
500+
}
501+
502+
ASImageDownloaderProgressImage progress = nil;
503+
if (shouldRenderProgressImages && ASInterfaceStateIncludesVisible(interfaceState)) {
504+
__weak __typeof__(self) weakSelf = self;
505+
progress = ^(UIImage * _Nonnull progressImage, CGFloat progress, id _Nullable downloadIdentifier) {
506+
__typeof__(self) strongSelf = weakSelf;
507+
if (strongSelf == nil) {
466508
return;
467-
}
468-
469-
ASImageDownloaderProgressImage progress = nil;
470-
if (ASInterfaceStateIncludesVisible(interfaceState)) {
471-
__weak __typeof__(self) weakSelf = self;
472-
progress = ^(UIImage * _Nonnull progressImage, CGFloat progress, id _Nullable downloadIdentifier) {
473-
__typeof__(self) strongSelf = weakSelf;
474-
if (strongSelf == nil) {
475-
return;
476-
}
477-
478-
ASDN::MutexLocker l(strongSelf->_downloadIdentifierLock);
479-
//Getting a result back for a different download identifier, download must not have been successfully canceled
480-
if (ASObjectIsEqual(strongSelf->_downloadIdentifier, downloadIdentifier) == NO && downloadIdentifier != nil) {
481-
return;
482-
}
483-
strongSelf.image = progressImage;
484-
};
485-
}
486-
[_downloader setProgressImageBlock:progress callbackQueue:dispatch_get_main_queue() withDownloadIdentifier:_downloadIdentifier];
509+
}
510+
511+
ASDN::MutexLocker l(strongSelf->_downloadIdentifierLock);
512+
//Getting a result back for a different download identifier, download must not have been successfully canceled
513+
if (ASObjectIsEqual(strongSelf->_downloadIdentifier, downloadIdentifier) == NO && downloadIdentifier != nil) {
514+
return;
515+
}
516+
strongSelf.image = progressImage;
517+
};
518+
}
519+
[_downloader setProgressImageBlock:progress callbackQueue:dispatch_get_main_queue() withDownloadIdentifier:_downloadIdentifier];
487520
}
488521

489522
- (void)_clearImage
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
//
2+
// ASNavigationController.h
3+
// Pods
4+
//
5+
// Created by Garrett Moon on 4/27/16.
6+
//
7+
//
8+
9+
#import <UIKit/UIKit.h>
10+
11+
#import "ASVisibilityProtocols.h"
12+
13+
@interface ASNavigationController : UINavigationController <ASManagesChildVisibilityDepth>
14+
15+
@end
Lines changed: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,93 @@
1+
//
2+
// ASNavigationController.m
3+
// Pods
4+
//
5+
// Created by Garrett Moon on 4/27/16.
6+
//
7+
//
8+
9+
#import "ASNavigationController.h"
10+
11+
@implementation ASNavigationController
12+
{
13+
BOOL _parentManagesVisibilityDepth;
14+
NSInteger _visibilityDepth;
15+
}
16+
17+
ASVisibilityDidMoveToParentViewController;
18+
19+
ASVisibilityViewWillAppear;
20+
21+
ASVisibilityViewDidDisappearImplementation;
22+
23+
ASVisibilitySetVisibilityDepth;
24+
25+
ASVisibilityDepthImplementation;
26+
27+
- (void)visibilityDepthDidChange
28+
{
29+
for (UIViewController *viewController in self.viewControllers) {
30+
if ([viewController conformsToProtocol:@protocol(ASVisibilityDepth)]) {
31+
[(id <ASVisibilityDepth>)viewController visibilityDepthDidChange];
32+
}
33+
}
34+
}
35+
36+
- (NSInteger)visibilityDepthOfChildViewController:(UIViewController *)childViewController
37+
{
38+
NSUInteger viewControllerIndex = [self.viewControllers indexOfObject:childViewController];
39+
NSAssert(viewControllerIndex != NSNotFound, @"childViewController is not in the navigation stack.");
40+
41+
if (viewControllerIndex == self.viewControllers.count - 1) {
42+
//view controller is at the top, just return our own visibility depth.
43+
return [self visibilityDepth];
44+
} else if (viewControllerIndex == 0) {
45+
//view controller is the root view controller. Can be accessed by holding the back button.
46+
return [self visibilityDepth] + 1;
47+
}
48+
49+
return [self visibilityDepth] + self.viewControllers.count - 1 - viewControllerIndex;
50+
}
51+
52+
#pragma mark - UIKit overrides
53+
54+
- (NSArray *)popToViewController:(UIViewController *)viewController animated:(BOOL)animated
55+
{
56+
NSArray *viewControllers = [super popToViewController:viewController animated:animated];
57+
[self visibilityDepthDidChange];
58+
return viewControllers;
59+
}
60+
61+
- (NSArray *)popToRootViewControllerAnimated:(BOOL)animated
62+
{
63+
NSArray *viewControllers = [super popToRootViewControllerAnimated:animated];
64+
[self visibilityDepthDidChange];
65+
return viewControllers;
66+
}
67+
68+
- (void)setViewControllers:(NSArray *)viewControllers
69+
{
70+
[super setViewControllers:viewControllers];
71+
[self visibilityDepthDidChange];
72+
}
73+
74+
- (void)setViewControllers:(NSArray *)viewControllers animated:(BOOL)animated
75+
{
76+
[super setViewControllers:viewControllers animated:animated];
77+
[self visibilityDepthDidChange];
78+
}
79+
80+
- (void)pushViewController:(UIViewController *)viewController animated:(BOOL)animated
81+
{
82+
[super pushViewController:viewController animated:animated];
83+
[self visibilityDepthDidChange];
84+
}
85+
86+
- (UIViewController *)popViewControllerAnimated:(BOOL)animated
87+
{
88+
UIViewController *viewController = [super popViewControllerAnimated:animated];
89+
[self visibilityDepthDidChange];
90+
return viewController;
91+
}
92+
93+
@end

AsyncDisplayKit/ASNetworkImageNode.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,13 @@ NS_ASSUME_NONNULL_BEGIN
7373
*/
7474
@property (nonatomic, assign, readwrite) BOOL shouldCacheImage;
7575

76+
/**
77+
* If the downloader implements progressive image rendering and this value is YES progressive renders of the
78+
* image will be displayed as the image downloads. Regardless of this properties value, progress renders will
79+
* only occur when the node is visible. Defaults to YES.
80+
*/
81+
@property (nonatomic, assign, readwrite) BOOL shouldRenderProgressImages;
82+
7683
/**
7784
* The image quality of the current image. This is a number between 0 and 1 and can be used to track
7885
* progressive progress. Calculated by dividing number of bytes / expected number of total bytes.

0 commit comments

Comments
 (0)