mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-12-23 22:55:00 +00:00
Merge remote-tracking branch 'facebook/master'
This commit is contained in:
@@ -600,6 +600,7 @@
|
||||
E5711A2C1C840C81009619D4 /* ASIndexedNodeContext.h in Headers */ = {isa = PBXBuildFile; fileRef = E5711A2A1C840C81009619D4 /* ASIndexedNodeContext.h */; };
|
||||
E5711A2E1C840C96009619D4 /* ASIndexedNodeContext.mm in Sources */ = {isa = PBXBuildFile; fileRef = E5711A2D1C840C96009619D4 /* ASIndexedNodeContext.mm */; };
|
||||
E5711A301C840C96009619D4 /* ASIndexedNodeContext.mm in Sources */ = {isa = PBXBuildFile; fileRef = E5711A2D1C840C96009619D4 /* ASIndexedNodeContext.mm */; };
|
||||
F711994E1D20C21100568860 /* ASDisplayNodeExtrasTests.m in Sources */ = {isa = PBXBuildFile; fileRef = F711994D1D20C21100568860 /* ASDisplayNodeExtrasTests.m */; };
|
||||
/* End PBXBuildFile section */
|
||||
|
||||
/* Begin PBXContainerItemProxy section */
|
||||
@@ -971,6 +972,7 @@
|
||||
E5711A2A1C840C81009619D4 /* ASIndexedNodeContext.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ASIndexedNodeContext.h; sourceTree = "<group>"; };
|
||||
E5711A2D1C840C96009619D4 /* ASIndexedNodeContext.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = ASIndexedNodeContext.mm; sourceTree = "<group>"; };
|
||||
EFA731F0396842FF8AB635EE /* libPods-AsyncDisplayKitTests.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-AsyncDisplayKitTests.a"; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
F711994D1D20C21100568860 /* ASDisplayNodeExtrasTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ASDisplayNodeExtrasTests.m; sourceTree = "<group>"; };
|
||||
FB07EABBCF28656C6297BC2D /* Pods-AsyncDisplayKitTests.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-AsyncDisplayKitTests.debug.xcconfig"; path = "Pods/Target Support Files/Pods-AsyncDisplayKitTests/Pods-AsyncDisplayKitTests.debug.xcconfig"; sourceTree = "<group>"; };
|
||||
/* End PBXFileReference section */
|
||||
|
||||
@@ -1216,6 +1218,7 @@
|
||||
058D0A36195D057000B7D73C /* ASTextNodeTests.m */,
|
||||
058D0A37195D057000B7D73C /* ASTextNodeWordKernerTests.mm */,
|
||||
AEEC47E31C21D3D200EC1693 /* ASVideoNodeTests.m */,
|
||||
F711994D1D20C21100568860 /* ASDisplayNodeExtrasTests.m */,
|
||||
058D09C6195D04C000B7D73C /* Supporting Files */,
|
||||
052EE06A1A15A0D8002C6279 /* TestResources */,
|
||||
2538B6F21BC5D2A2003CA0B4 /* ASCollectionViewFlowLayoutInspectorTests.m */,
|
||||
@@ -2180,6 +2183,7 @@
|
||||
9F06E5CD1B4CAF4200F015D8 /* ASCollectionViewTests.m in Sources */,
|
||||
2911485C1A77147A005D0878 /* ASControlNodeTests.m in Sources */,
|
||||
CC3B208E1C3F7D0A00798563 /* ASWeakSetTests.m in Sources */,
|
||||
F711994E1D20C21100568860 /* ASDisplayNodeExtrasTests.m in Sources */,
|
||||
ACF6ED5D1B178DC700DA7C62 /* ASDimensionTests.mm in Sources */,
|
||||
058D0A38195D057000B7D73C /* ASDisplayLayerTests.m in Sources */,
|
||||
2538B6F31BC5D2A2003CA0B4 /* ASCollectionViewFlowLayoutInspectorTests.m in Sources */,
|
||||
|
||||
@@ -1543,27 +1543,20 @@ static NSInteger incrementIfFound(NSInteger i) {
|
||||
__weak UIView *view = _view;
|
||||
__weak CALayer *layer = _layer;
|
||||
BOOL layerBacked = _flags.layerBacked;
|
||||
BOOL isNodeLoaded = (layer != nil || view != nil);
|
||||
_propertyLock.unlock();
|
||||
|
||||
if (supernode == nil) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Clear supernode's reference to us before removing the view from the hierarchy, as _ASDisplayView
|
||||
// will trigger us to clear our _supernode pointer in willMoveToSuperview:nil.
|
||||
// This may result in removing the last strong reference, triggering deallocation after this method.
|
||||
[supernode _removeSubnode:self];
|
||||
|
||||
if (self.nodeLoaded && supernode.nodeLoaded) {
|
||||
// Check to ensure that our view or layer is actually inside of our supernode; otherwise, don't remove it.
|
||||
// Though _ASDisplayView decouples the supernode if it is inserted inside another view hierarchy, this is
|
||||
// more difficult to guarantee with _ASDisplayLayer because CoreAnimation doesn't have a -didMoveToSuperlayer.
|
||||
if (isNodeLoaded && (supernode == nil || supernode.isNodeLoaded)) {
|
||||
ASPerformBlockOnMainThread(^{
|
||||
if (layerBacked || supernode.layerBacked) {
|
||||
if (layer.superlayer == supernode.layer) {
|
||||
[layer removeFromSuperlayer];
|
||||
}
|
||||
[layer removeFromSuperlayer];
|
||||
} else {
|
||||
if (view.superview == supernode.view) {
|
||||
[view removeFromSuperview];
|
||||
}
|
||||
[view removeFromSuperview];
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@@ -144,7 +144,7 @@ static void _ASDisplayNodeFindAllSubnodes(NSMutableArray *array, ASDisplayNode *
|
||||
|
||||
for (ASDisplayNode *subnode in node.subnodes) {
|
||||
if (block(subnode)) {
|
||||
[array addObject:node];
|
||||
[array addObject:subnode];
|
||||
}
|
||||
|
||||
_ASDisplayNodeFindAllSubnodes(array, subnode, block);
|
||||
|
||||
@@ -43,24 +43,28 @@ static const CGSize kMinReleaseImageOnBackgroundSize = {20.0, 20.0};
|
||||
BOOL _imageLoaded;
|
||||
CGFloat _currentImageQuality;
|
||||
CGFloat _renderedImageQuality;
|
||||
|
||||
// TODO: Move this to flags
|
||||
BOOL _delegateSupportsDidStartFetchingData;
|
||||
BOOL _delegateSupportsDidFailWithError;
|
||||
BOOL _delegateSupportsDidFinishDecoding;
|
||||
BOOL _delegateSupportsDidLoadImage;
|
||||
|
||||
BOOL _shouldRenderProgressImages;
|
||||
|
||||
//set on init only
|
||||
BOOL _downloaderSupportsNewProtocol;
|
||||
BOOL _downloaderImplementsSetProgress;
|
||||
BOOL _downloaderImplementsSetPriority;
|
||||
BOOL _downloaderImplementsAnimatedImage;
|
||||
struct {
|
||||
unsigned int delegateDidStartFetchingData:1;
|
||||
unsigned int delegateDidFailWithError:1;
|
||||
unsigned int delegateDidFinishDecoding:1;
|
||||
unsigned int delegateDidLoadImage:1;
|
||||
} _delegateFlags;
|
||||
|
||||
BOOL _cacheSupportsNewProtocol;
|
||||
BOOL _cacheSupportsClearing;
|
||||
BOOL _cacheSupportsSynchronousFetch;
|
||||
//set on init only
|
||||
struct {
|
||||
unsigned int downloaderSupportsNewProtocol:1;
|
||||
unsigned int downloaderImplementsSetProgress:1;
|
||||
unsigned int downloaderImplementsSetPriority:1;
|
||||
unsigned int downloaderImplementsAnimatedImage:1;
|
||||
} _downloaderFlags;
|
||||
|
||||
struct {
|
||||
unsigned int cacheSupportsNewProtocol:1;
|
||||
unsigned int cacheSupportsClearing:1;
|
||||
unsigned int cacheSupportsSynchronousFetch:1;
|
||||
} _cacheFlags;
|
||||
}
|
||||
@end
|
||||
|
||||
@@ -76,17 +80,17 @@ static const CGSize kMinReleaseImageOnBackgroundSize = {20.0, 20.0};
|
||||
|
||||
ASDisplayNodeAssert([downloader respondsToSelector:@selector(downloadImageWithURL:callbackQueue:downloadProgress:completion:)] || [downloader respondsToSelector:@selector(downloadImageWithURL:callbackQueue:downloadProgressBlock:completion:)], @"downloader must respond to either downloadImageWithURL:callbackQueue:downloadProgress:completion: or downloadImageWithURL:callbackQueue:downloadProgressBlock:completion:.");
|
||||
|
||||
_downloaderSupportsNewProtocol = [downloader respondsToSelector:@selector(downloadImageWithURL:callbackQueue:downloadProgress:completion:)];
|
||||
_downloaderFlags.downloaderSupportsNewProtocol = [downloader respondsToSelector:@selector(downloadImageWithURL:callbackQueue:downloadProgress:completion:)];
|
||||
|
||||
ASDisplayNodeAssert(cache == nil || [cache respondsToSelector:@selector(cachedImageWithURL:callbackQueue:completion:)] || [cache respondsToSelector:@selector(fetchCachedImageWithURL:callbackQueue:completion:)], @"cacher must respond to either cachedImageWithURL:callbackQueue:completion: or fetchCachedImageWithURL:callbackQueue:completion:");
|
||||
|
||||
_downloaderImplementsSetProgress = [downloader respondsToSelector:@selector(setProgressImageBlock:callbackQueue:withDownloadIdentifier:)];
|
||||
_downloaderImplementsSetPriority = [downloader respondsToSelector:@selector(setPriority:withDownloadIdentifier:)];
|
||||
_downloaderImplementsAnimatedImage = [downloader respondsToSelector:@selector(animatedImageWithData:)];
|
||||
_downloaderFlags.downloaderImplementsSetProgress = [downloader respondsToSelector:@selector(setProgressImageBlock:callbackQueue:withDownloadIdentifier:)];
|
||||
_downloaderFlags.downloaderImplementsSetPriority = [downloader respondsToSelector:@selector(setPriority:withDownloadIdentifier:)];
|
||||
_downloaderFlags.downloaderImplementsAnimatedImage = [downloader respondsToSelector:@selector(animatedImageWithData:)];
|
||||
|
||||
_cacheSupportsNewProtocol = [cache respondsToSelector:@selector(cachedImageWithURL:callbackQueue:completion:)];
|
||||
_cacheSupportsClearing = [cache respondsToSelector:@selector(clearFetchedImageFromCacheWithURL:)];
|
||||
_cacheSupportsSynchronousFetch = [cache respondsToSelector:@selector(synchronouslyFetchedCachedImageWithURL:)];
|
||||
_cacheFlags.cacheSupportsNewProtocol = [cache respondsToSelector:@selector(cachedImageWithURL:callbackQueue:completion:)];
|
||||
_cacheFlags.cacheSupportsClearing = [cache respondsToSelector:@selector(clearFetchedImageFromCacheWithURL:)];
|
||||
_cacheFlags.cacheSupportsSynchronousFetch = [cache respondsToSelector:@selector(synchronouslyFetchedCachedImageWithURL:)];
|
||||
|
||||
_shouldCacheImage = YES;
|
||||
_shouldRenderProgressImages = YES;
|
||||
@@ -214,10 +218,10 @@ static const CGSize kMinReleaseImageOnBackgroundSize = {20.0, 20.0};
|
||||
ASDN::MutexLocker l(_lock);
|
||||
_delegate = delegate;
|
||||
|
||||
_delegateSupportsDidStartFetchingData = [delegate respondsToSelector:@selector(imageNodeDidStartFetchingData:)];
|
||||
_delegateSupportsDidFailWithError = [delegate respondsToSelector:@selector(imageNode:didFailWithError:)];
|
||||
_delegateSupportsDidFinishDecoding = [delegate respondsToSelector:@selector(imageNodeDidFinishDecoding:)];
|
||||
_delegateSupportsDidLoadImage = [delegate respondsToSelector:@selector(imageNode:didLoadImage:)];
|
||||
_delegateFlags.delegateDidStartFetchingData = [delegate respondsToSelector:@selector(imageNodeDidStartFetchingData:)];
|
||||
_delegateFlags.delegateDidFailWithError = [delegate respondsToSelector:@selector(imageNode:didFailWithError:)];
|
||||
_delegateFlags.delegateDidFinishDecoding = [delegate respondsToSelector:@selector(imageNodeDidFinishDecoding:)];
|
||||
_delegateFlags.delegateDidLoadImage = [delegate respondsToSelector:@selector(imageNode:didLoadImage:)];
|
||||
}
|
||||
|
||||
- (id<ASNetworkImageNodeDelegate>)delegate
|
||||
@@ -258,7 +262,7 @@ static const CGSize kMinReleaseImageOnBackgroundSize = {20.0, 20.0};
|
||||
{
|
||||
[super displayWillStart];
|
||||
|
||||
if (_cacheSupportsSynchronousFetch) {
|
||||
if (_cacheFlags.cacheSupportsSynchronousFetch) {
|
||||
ASDN::MutexLocker l(_lock);
|
||||
if (_imageLoaded == NO && _URL && _downloadIdentifier == nil) {
|
||||
UIImage *result = [[_cache synchronouslyFetchedCachedImageWithURL:_URL] asdk_image];
|
||||
@@ -275,7 +279,7 @@ static const CGSize kMinReleaseImageOnBackgroundSize = {20.0, 20.0};
|
||||
// TODO: Consider removing this; it predates ASInterfaceState, which now ensures that even non-range-managed nodes get a -fetchData call.
|
||||
[self fetchData];
|
||||
|
||||
if (self.image == nil && _downloaderImplementsSetPriority) {
|
||||
if (self.image == nil && _downloaderFlags.downloaderImplementsSetPriority) {
|
||||
ASDN::MutexLocker l(_lock);
|
||||
if (_downloadIdentifier != nil) {
|
||||
[_downloader setPriority:ASImageDownloaderPriorityImminent withDownloadIdentifier:_downloadIdentifier];
|
||||
@@ -289,7 +293,7 @@ static const CGSize kMinReleaseImageOnBackgroundSize = {20.0, 20.0};
|
||||
{
|
||||
[super visibleStateDidChange:isVisible];
|
||||
|
||||
if (_downloaderImplementsSetPriority) {
|
||||
if (_downloaderFlags.downloaderImplementsSetPriority) {
|
||||
_lock.lock();
|
||||
if (_downloadIdentifier != nil) {
|
||||
if (isVisible) {
|
||||
@@ -314,7 +318,7 @@ static const CGSize kMinReleaseImageOnBackgroundSize = {20.0, 20.0};
|
||||
|
||||
[self _cancelImageDownload];
|
||||
[self _clearImage];
|
||||
if (_cacheSupportsClearing) {
|
||||
if (_cacheFlags.cacheSupportsClearing) {
|
||||
[_cache clearFetchedImageFromCacheWithURL:_URL];
|
||||
}
|
||||
}
|
||||
@@ -344,7 +348,7 @@ static const CGSize kMinReleaseImageOnBackgroundSize = {20.0, 20.0};
|
||||
ASInterfaceState interfaceState = self.interfaceState;
|
||||
ASDN::MutexLocker l(_lock);
|
||||
|
||||
if (!_downloaderImplementsSetProgress || _downloadIdentifier == nil) {
|
||||
if (!_downloaderFlags.downloaderImplementsSetProgress || _downloadIdentifier == nil) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -411,7 +415,7 @@ static const CGSize kMinReleaseImageOnBackgroundSize = {20.0, 20.0};
|
||||
{
|
||||
ASPerformBlockOnBackgroundThread(^{
|
||||
_lock.lock();
|
||||
if (_downloaderSupportsNewProtocol) {
|
||||
if (_downloaderFlags.downloaderSupportsNewProtocol) {
|
||||
_downloadIdentifier = [_downloader downloadImageWithURL:_URL
|
||||
callbackQueue:dispatch_get_main_queue()
|
||||
downloadProgress:NULL
|
||||
@@ -447,7 +451,7 @@ static const CGSize kMinReleaseImageOnBackgroundSize = {20.0, 20.0};
|
||||
if (!_imageLoaded && _URL != nil && _downloadIdentifier == nil) {
|
||||
{
|
||||
ASDN::MutexLocker l(_lock);
|
||||
if (_delegateSupportsDidStartFetchingData) {
|
||||
if (_delegateFlags.delegateDidStartFetchingData) {
|
||||
[_delegate imageNodeDidStartFetchingData:self];
|
||||
}
|
||||
}
|
||||
@@ -474,7 +478,7 @@ static const CGSize kMinReleaseImageOnBackgroundSize = {20.0, 20.0};
|
||||
|
||||
// If the file may be an animated gif and then created an animated image.
|
||||
id<ASAnimatedImageProtocol> animatedImage = nil;
|
||||
if (_downloaderImplementsAnimatedImage) {
|
||||
if (_downloaderFlags.downloaderImplementsAnimatedImage) {
|
||||
NSData *data = [NSData dataWithContentsOfURL:_URL];
|
||||
animatedImage = [_downloader animatedImageWithData:data];
|
||||
|
||||
@@ -497,7 +501,7 @@ static const CGSize kMinReleaseImageOnBackgroundSize = {20.0, 20.0};
|
||||
dispatch_async(dispatch_get_main_queue(), ^{
|
||||
self.currentImageQuality = 1.0;
|
||||
});
|
||||
if (_delegateSupportsDidLoadImage) {
|
||||
if (_delegateFlags.delegateDidLoadImage) {
|
||||
[_delegate imageNode:self didLoadImage:self.image];
|
||||
}
|
||||
});
|
||||
@@ -519,7 +523,7 @@ static const CGSize kMinReleaseImageOnBackgroundSize = {20.0, 20.0};
|
||||
|
||||
if (imageContainer != nil) {
|
||||
strongSelf->_imageLoaded = YES;
|
||||
if ([imageContainer asdk_animatedImageData] && _downloaderImplementsAnimatedImage) {
|
||||
if ([imageContainer asdk_animatedImageData] && _downloaderFlags.downloaderImplementsAnimatedImage) {
|
||||
strongSelf.animatedImage = [_downloader animatedImageWithData:[imageContainer asdk_animatedImageData]];
|
||||
} else {
|
||||
strongSelf.image = [imageContainer asdk_image];
|
||||
@@ -534,11 +538,11 @@ static const CGSize kMinReleaseImageOnBackgroundSize = {20.0, 20.0};
|
||||
strongSelf->_cacheUUID = nil;
|
||||
|
||||
if (imageContainer != nil) {
|
||||
if (strongSelf->_delegateSupportsDidLoadImage) {
|
||||
if (strongSelf->_delegateFlags.delegateDidLoadImage) {
|
||||
[strongSelf->_delegate imageNode:strongSelf didLoadImage:strongSelf.image];
|
||||
}
|
||||
}
|
||||
else if (error && strongSelf->_delegateSupportsDidFailWithError) {
|
||||
else if (error && strongSelf->_delegateFlags.delegateDidFailWithError) {
|
||||
[strongSelf->_delegate imageNode:strongSelf didFailWithError:error];
|
||||
}
|
||||
};
|
||||
@@ -560,7 +564,7 @@ static const CGSize kMinReleaseImageOnBackgroundSize = {20.0, 20.0};
|
||||
}
|
||||
};
|
||||
|
||||
if (_cacheSupportsNewProtocol) {
|
||||
if (_cacheFlags.cacheSupportsNewProtocol) {
|
||||
[_cache cachedImageWithURL:_URL
|
||||
callbackQueue:dispatch_get_main_queue()
|
||||
completion:cacheCompletion];
|
||||
@@ -588,7 +592,7 @@ static const CGSize kMinReleaseImageOnBackgroundSize = {20.0, 20.0};
|
||||
[super displayDidFinish];
|
||||
|
||||
ASDN::MutexLocker l(_lock);
|
||||
if (_delegateSupportsDidFinishDecoding && self.layer.contents != nil) {
|
||||
if (_delegateFlags.delegateDidFinishDecoding && self.layer.contents != nil) {
|
||||
/* We store the image quality in _currentImageQuality whenever _image is set. On the following displayDidFinish, we'll know that
|
||||
_currentImageQuality is the quality of the image that has just finished rendering. In order for this to be accurate, we
|
||||
need to be sure we are on main thread when we set _currentImageQuality. Otherwise, it is possible for _currentImageQuality
|
||||
|
||||
@@ -151,7 +151,7 @@ static NSString * const kStatus = @"status";
|
||||
self.player = [AVPlayer playerWithPlayerItem:playerItem];
|
||||
}
|
||||
|
||||
if (self.image == nil) {
|
||||
if (self.image == nil && self.URL == nil) {
|
||||
[self generatePlaceholderImage];
|
||||
}
|
||||
|
||||
@@ -288,7 +288,7 @@ static NSString * const kStatus = @"status";
|
||||
if ([change[NSKeyValueChangeNewKey] integerValue] == AVPlayerItemStatusReadyToPlay) {
|
||||
self.playerState = ASVideoNodePlayerStateReadyToPlay;
|
||||
// If we don't yet have a placeholder image update it now that we should have data available for it
|
||||
if (self.image == nil) {
|
||||
if (self.image == nil && self.URL == nil) {
|
||||
[self generatePlaceholderImage];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,22 +18,19 @@
|
||||
|
||||
#import "ASDataController+Subclasses.h"
|
||||
|
||||
@interface ASChangeSetDataController ()
|
||||
|
||||
@property (nonatomic, assign) NSUInteger changeSetBatchUpdateCounter;
|
||||
@property (nonatomic, strong) _ASHierarchyChangeSet *changeSet;
|
||||
|
||||
@end
|
||||
|
||||
@implementation ASChangeSetDataController
|
||||
@implementation ASChangeSetDataController {
|
||||
NSInteger _changeSetBatchUpdateCounter;
|
||||
_ASHierarchyChangeSet *_changeSet;
|
||||
}
|
||||
|
||||
#pragma mark - Batching (External API)
|
||||
|
||||
- (void)beginUpdates
|
||||
{
|
||||
ASDisplayNodeAssertMainThread();
|
||||
if (_changeSetBatchUpdateCounter == 0) {
|
||||
if (_changeSetBatchUpdateCounter <= 0) {
|
||||
_changeSet = [_ASHierarchyChangeSet new];
|
||||
_changeSetBatchUpdateCounter = 0;
|
||||
}
|
||||
_changeSetBatchUpdateCounter++;
|
||||
}
|
||||
@@ -43,6 +40,9 @@
|
||||
ASDisplayNodeAssertMainThread();
|
||||
_changeSetBatchUpdateCounter--;
|
||||
|
||||
// Prevent calling endUpdatesAnimated:completion: in an unbalanced way
|
||||
NSAssert(_changeSetBatchUpdateCounter >= 0, @"endUpdatesAnimated:completion: called without having a balanced beginUpdates call");
|
||||
|
||||
if (_changeSetBatchUpdateCounter == 0) {
|
||||
[_changeSet markCompleted];
|
||||
|
||||
|
||||
@@ -86,8 +86,7 @@
|
||||
UIView *currentSuperview = self.superview;
|
||||
if (!currentSuperview && newSuperview) {
|
||||
self.keepalive_node = _node;
|
||||
}
|
||||
else if (currentSuperview && !newSuperview) {
|
||||
} else if (currentSuperview && !newSuperview) {
|
||||
// Clearing keepalive_node may cause deallocation of the node. In this case, __exitHierarchy may not have an opportunity (e.g. _node will be cleared
|
||||
// by the time -didMoveToWindow occurs after this) to clear the Visible interfaceState, which we need to do before deallocation to meet an API guarantee.
|
||||
if (_node.inHierarchy) {
|
||||
@@ -95,6 +94,8 @@
|
||||
}
|
||||
self.keepalive_node = nil;
|
||||
}
|
||||
|
||||
ASDisplayNodeAssert(self.keepalive_node == nil || newSuperview != nil, @"Keepalive reference should not exist if there is no superview.");
|
||||
|
||||
if (newSuperview) {
|
||||
ASDisplayNode *supernode = _node.supernode;
|
||||
|
||||
76
AsyncDisplayKitTests/ASDisplayNodeExtrasTests.m
Normal file
76
AsyncDisplayKitTests/ASDisplayNodeExtrasTests.m
Normal file
@@ -0,0 +1,76 @@
|
||||
//
|
||||
// ASDisplayNodeExtrasTests.m
|
||||
// AsyncDisplayKit
|
||||
//
|
||||
// Created by Kiel Gillard on 27/06/2016.
|
||||
// Copyright © 2016 Facebook. All rights reserved.
|
||||
//
|
||||
|
||||
#import <XCTest/XCTest.h>
|
||||
#import <AsyncDisplayKit/AsyncDisplayKit.h>
|
||||
#import <AsyncDisplayKit/ASDisplayNodeExtras.h>
|
||||
|
||||
@interface ASDisplayNodeExtrasTests : XCTestCase
|
||||
|
||||
@end
|
||||
|
||||
@interface TestDisplayNode : ASDisplayNode
|
||||
@end
|
||||
|
||||
@implementation TestDisplayNode
|
||||
@end
|
||||
|
||||
@implementation ASDisplayNodeExtrasTests
|
||||
|
||||
- (void)testShallowFindSubnodesOfSubclass {
|
||||
ASDisplayNode *supernode = [[ASDisplayNode alloc] initWithLayerBlock:^CALayer * _Nonnull{
|
||||
return [CALayer layer];
|
||||
}];
|
||||
NSUInteger count = 10;
|
||||
NSMutableArray *expected = [[NSMutableArray alloc] initWithCapacity:count];
|
||||
for (NSUInteger nodeIndex = 0; nodeIndex < count; nodeIndex++) {
|
||||
TestDisplayNode *node = [[TestDisplayNode alloc] initWithLayerBlock:^CALayer * _Nonnull{
|
||||
return [CALayer layer];
|
||||
}];
|
||||
[supernode addSubnode:node];
|
||||
[expected addObject:node];
|
||||
}
|
||||
NSArray *found = ASDisplayNodeFindAllSubnodesOfClass(supernode, [TestDisplayNode class]);
|
||||
XCTAssertEqualObjects(found, expected, @"Expecting %lu %@ nodes, found %lu", (unsigned long)count, [TestDisplayNode class], (unsigned long)found.count);
|
||||
}
|
||||
|
||||
- (void)testDeepFindSubnodesOfSubclass {
|
||||
ASDisplayNode *supernode = [[ASDisplayNode alloc] initWithLayerBlock:^CALayer * _Nonnull{
|
||||
return [CALayer layer];
|
||||
}];
|
||||
|
||||
const NSUInteger count = 2;
|
||||
const NSUInteger levels = 2;
|
||||
const NSUInteger capacity = [[self class] capacityForCount:count levels:levels];
|
||||
NSMutableArray *expected = [[NSMutableArray alloc] initWithCapacity:capacity];
|
||||
|
||||
[[self class] addSubnodesToNode:supernode number:count remainingLevels:levels accumulated:expected];
|
||||
|
||||
NSArray *found = ASDisplayNodeFindAllSubnodesOfClass(supernode, [TestDisplayNode class]);
|
||||
XCTAssertEqualObjects(found, expected, @"Expecting %lu %@ nodes, found %lu", (unsigned long)count, [TestDisplayNode class], (unsigned long)found.count);
|
||||
}
|
||||
|
||||
+ (void)addSubnodesToNode:(ASDisplayNode *)supernode number:(NSUInteger)number remainingLevels:(NSUInteger)level accumulated:(inout NSMutableArray *)expected {
|
||||
if (level == 0) return;
|
||||
for (NSUInteger nodeIndex = 0; nodeIndex < number; nodeIndex++) {
|
||||
TestDisplayNode *node = [[TestDisplayNode alloc] initWithLayerBlock:^CALayer * _Nonnull{
|
||||
return [CALayer layer];
|
||||
}];
|
||||
[supernode addSubnode:node];
|
||||
[expected addObject:node];
|
||||
[self addSubnodesToNode:node number:number remainingLevels:(level - 1) accumulated:expected];
|
||||
}
|
||||
}
|
||||
|
||||
// Graph theory is failing me atm.
|
||||
+ (NSUInteger)capacityForCount:(NSUInteger)count levels:(NSUInteger)level {
|
||||
if (level == 0) return 0;
|
||||
return pow(count, level) + [self capacityForCount:count levels:(level - 1)];
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -46,6 +46,9 @@
|
||||
ASVideoNode *simonVideoNode = self.simonVideoNode;
|
||||
[_rootNode addSubnode:simonVideoNode];
|
||||
|
||||
ASVideoNode *hlsVideoNode = self.hlsVideoNode;
|
||||
[_rootNode addSubnode:hlsVideoNode];
|
||||
|
||||
_rootNode.layoutSpecBlock = ^ASLayoutSpec *(ASDisplayNode * _Nonnull node, ASSizeRange constrainedSize) {
|
||||
guitarVideoNode.layoutPosition = CGPointMake(0, 0);
|
||||
guitarVideoNode.preferredFrameSize = CGSizeMake([UIScreen mainScreen].bounds.size.width, [UIScreen mainScreen].bounds.size.height/3);
|
||||
@@ -55,8 +58,13 @@
|
||||
|
||||
simonVideoNode.layoutPosition = CGPointMake(0, [UIScreen mainScreen].bounds.size.height - ([UIScreen mainScreen].bounds.size.height/3));
|
||||
simonVideoNode.preferredFrameSize = CGSizeMake([UIScreen mainScreen].bounds.size.width/2, [UIScreen mainScreen].bounds.size.height/3);
|
||||
return [ASStaticLayoutSpec staticLayoutSpecWithChildren:@[guitarVideoNode, nicCageVideoNode, simonVideoNode]];
|
||||
|
||||
hlsVideoNode.layoutPosition = CGPointMake(0, [UIScreen mainScreen].bounds.size.height/3);
|
||||
hlsVideoNode.preferredFrameSize = CGSizeMake([UIScreen mainScreen].bounds.size.width/2, [UIScreen mainScreen].bounds.size.height/3);
|
||||
|
||||
return [ASStaticLayoutSpec staticLayoutSpecWithChildren:@[guitarVideoNode, nicCageVideoNode, simonVideoNode, hlsVideoNode]];
|
||||
};
|
||||
|
||||
[self.view addSubnode:_rootNode];
|
||||
}
|
||||
|
||||
@@ -117,6 +125,24 @@
|
||||
return simonVideoNode;
|
||||
}
|
||||
|
||||
- (ASVideoNode *)hlsVideoNode;
|
||||
{
|
||||
ASVideoNode *hlsVideoNode = [[ASVideoNode alloc] init];
|
||||
|
||||
hlsVideoNode.delegate = self;
|
||||
hlsVideoNode.asset = [AVAsset assetWithURL:[NSURL URLWithString:@"http://devimages.apple.com/iphone/samples/bipbop/gear1/prog_index.m3u8"]];
|
||||
hlsVideoNode.gravity = AVLayerVideoGravityResize;
|
||||
hlsVideoNode.backgroundColor = [UIColor lightGrayColor];
|
||||
hlsVideoNode.shouldAutorepeat = YES;
|
||||
hlsVideoNode.shouldAutoplay = YES;
|
||||
hlsVideoNode.muted = YES;
|
||||
|
||||
// Placeholder image
|
||||
hlsVideoNode.URL = [NSURL URLWithString:@"https://upload.wikimedia.org/wikipedia/en/5/52/Testcard_F.jpg"];
|
||||
|
||||
return hlsVideoNode;
|
||||
}
|
||||
|
||||
- (ASButtonNode *)playButton;
|
||||
{
|
||||
ASButtonNode *playButtonNode = [[ASButtonNode alloc] init];
|
||||
|
||||
Reference in New Issue
Block a user