mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-12-16 11:20:18 +00:00
Several bug fixes for the 1.0 release of AsyncDisplayKit
Fixes: - Usage of UIScreen in -[ASDisplayNode init] (the offending individual will be prosecuted) - #38: Proper teardown of nodes owned by ASTableView / ASRangeController - #34: Fix infinite recursion in very rare subclassing scenario - #30: Avoid animating cell and section additions to ASTableView - #19: Set a more reasonable default for maximum display concurrency r=nadi
This commit is contained in:
parent
f7d91bb877
commit
c61b1c294c
@ -47,6 +47,22 @@ BOOL ASDisplayNodeSubclassOverridesSelector(Class subclass, SEL selector)
|
|||||||
return (superclassIMP != subclassIMP);
|
return (superclassIMP != subclassIMP);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
CGFloat ASDisplayNodeScreenScale()
|
||||||
|
{
|
||||||
|
static CGFloat screenScale = 0.0;
|
||||||
|
static dispatch_once_t onceToken;
|
||||||
|
dispatch_once(&onceToken, ^{
|
||||||
|
if ([NSThread isMainThread]) {
|
||||||
|
screenScale = [[UIScreen mainScreen] scale];
|
||||||
|
} else {
|
||||||
|
dispatch_sync(dispatch_get_main_queue(), ^{
|
||||||
|
screenScale = [[UIScreen mainScreen] scale];
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return screenScale;
|
||||||
|
}
|
||||||
|
|
||||||
+ (void)initialize
|
+ (void)initialize
|
||||||
{
|
{
|
||||||
if (self == [ASDisplayNode class]) {
|
if (self == [ASDisplayNode class]) {
|
||||||
@ -74,14 +90,44 @@ BOOL ASDisplayNodeSubclassOverridesSelector(Class subclass, SEL selector)
|
|||||||
return [_ASDisplayLayer class];
|
return [_ASDisplayLayer class];
|
||||||
}
|
}
|
||||||
|
|
||||||
#pragma mark - NSObject Overrides
|
#pragma mark - Lifecycle
|
||||||
|
|
||||||
|
// Avoid recursive loops if a subclass implements an init method that calls -initWith*Class:
|
||||||
|
- (void)_initializeInstance
|
||||||
|
{
|
||||||
|
_contentsScaleForDisplay = ASDisplayNodeScreenScale();
|
||||||
|
|
||||||
|
_displaySentinel = [[ASSentinel alloc] init];
|
||||||
|
|
||||||
|
_flags.inWindow = NO;
|
||||||
|
_flags.displaysAsynchronously = YES;
|
||||||
|
|
||||||
|
// As an optimization, it may be worth a caching system that performs these checks once per class in +initialize (see above).
|
||||||
|
_flags.implementsDisplay = [[self class] respondsToSelector:@selector(drawRect:withParameters:isCancelled:isRasterizing:)] || [self.class respondsToSelector:@selector(displayWithParameters:isCancelled:)];
|
||||||
|
|
||||||
|
_flags.hasClassDisplay = ([[self class] respondsToSelector:@selector(displayWithParameters:isCancelled:)] ? 1 : 0);
|
||||||
|
_flags.hasWillDisplayAsyncLayer = ([self respondsToSelector:@selector(willDisplayAsyncLayer:)] ? 1 : 0);
|
||||||
|
_flags.hasDrawParametersForAsyncLayer = ([self respondsToSelector:@selector(drawParametersForAsyncLayer:)] ? 1 : 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
- (id)init
|
||||||
|
{
|
||||||
|
if (!(self = [super init]))
|
||||||
|
return nil;
|
||||||
|
|
||||||
|
[self _initializeInstance];
|
||||||
|
|
||||||
|
return self;
|
||||||
|
}
|
||||||
|
|
||||||
- (id)initWithViewClass:(Class)viewClass
|
- (id)initWithViewClass:(Class)viewClass
|
||||||
{
|
{
|
||||||
if (!(self = [self init]))
|
if (!(self = [super init]))
|
||||||
return nil;
|
return nil;
|
||||||
|
|
||||||
ASDisplayNodeAssert([viewClass isSubclassOfClass:[UIView class]], @"should initialize with a subclass of UIView");
|
ASDisplayNodeAssert([viewClass isSubclassOfClass:[UIView class]], @"should initialize with a subclass of UIView");
|
||||||
|
|
||||||
|
[self _initializeInstance];
|
||||||
_viewClass = viewClass;
|
_viewClass = viewClass;
|
||||||
_flags.isSynchronous = ![viewClass isSubclassOfClass:[_ASDisplayView class]];
|
_flags.isSynchronous = ![viewClass isSubclassOfClass:[_ASDisplayView class]];
|
||||||
|
|
||||||
@ -90,40 +136,19 @@ BOOL ASDisplayNodeSubclassOverridesSelector(Class subclass, SEL selector)
|
|||||||
|
|
||||||
- (id)initWithLayerClass:(Class)layerClass
|
- (id)initWithLayerClass:(Class)layerClass
|
||||||
{
|
{
|
||||||
if (!(self = [self init]))
|
if (!(self = [super init]))
|
||||||
return nil;
|
return nil;
|
||||||
|
|
||||||
ASDisplayNodeAssert([layerClass isSubclassOfClass:[CALayer class]], @"should initialize with a subclass of CALayer");
|
ASDisplayNodeAssert([layerClass isSubclassOfClass:[CALayer class]], @"should initialize with a subclass of CALayer");
|
||||||
|
|
||||||
|
[self _initializeInstance];
|
||||||
_layerClass = layerClass;
|
_layerClass = layerClass;
|
||||||
_flags.isSynchronous = ![layerClass isSubclassOfClass:[_ASDisplayLayer class]];
|
_flags.isSynchronous = ![layerClass isSubclassOfClass:[_ASDisplayLayer class]];
|
||||||
|
|
||||||
_flags.isLayerBacked = YES;
|
_flags.isLayerBacked = YES;
|
||||||
|
|
||||||
return self;
|
return self;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (id)init
|
|
||||||
{
|
|
||||||
self = [super init];
|
|
||||||
if (!self) return nil;
|
|
||||||
|
|
||||||
_contentsScaleForDisplay = [[UIScreen mainScreen] scale];
|
|
||||||
|
|
||||||
_displaySentinel = [[ASSentinel alloc] init];
|
|
||||||
|
|
||||||
_flags.inWindow = NO;
|
|
||||||
_flags.displaysAsynchronously = YES;
|
|
||||||
|
|
||||||
_flags.implementsDisplay = [[self class] respondsToSelector:@selector(drawRect:withParameters:isCancelled:isRasterizing:)] || [self.class respondsToSelector:@selector(displayWithParameters:isCancelled:)];
|
|
||||||
|
|
||||||
_flags.hasWillDisplayAsyncLayer = ([self respondsToSelector:@selector(willDisplayAsyncLayer:)] ? 1 : 0);
|
|
||||||
_flags.hasClassDisplay = ([[self class] respondsToSelector:@selector(displayWithParameters:isCancelled:)] ? 1 : 0);
|
|
||||||
_flags.hasDrawParametersForAsyncLayer = ([self respondsToSelector:@selector(drawParametersForAsyncLayer:)] ? 1 : 0);
|
|
||||||
|
|
||||||
return self;
|
|
||||||
}
|
|
||||||
|
|
||||||
- (void)dealloc
|
- (void)dealloc
|
||||||
{
|
{
|
||||||
ASDisplayNodeAssertMainThread();
|
ASDisplayNodeAssertMainThread();
|
||||||
@ -142,9 +167,8 @@ BOOL ASDisplayNodeSubclassOverridesSelector(Class subclass, SEL selector)
|
|||||||
|
|
||||||
_view = nil;
|
_view = nil;
|
||||||
_subnodes = nil;
|
_subnodes = nil;
|
||||||
if (_flags.isLayerBacked) {
|
if (_flags.isLayerBacked)
|
||||||
_layer.delegate = nil;
|
_layer.delegate = nil;
|
||||||
}
|
|
||||||
_layer = nil;
|
_layer = nil;
|
||||||
|
|
||||||
[self __setSupernode:nil];
|
[self __setSupernode:nil];
|
||||||
|
|||||||
@ -355,10 +355,10 @@ static BOOL _isInterceptedSelector(SEL sel)
|
|||||||
if (newSectionCount > sectionCount) {
|
if (newSectionCount > sectionCount) {
|
||||||
NSRange range = NSMakeRange(sectionCount, newSectionCount - sectionCount);
|
NSRange range = NSMakeRange(sectionCount, newSectionCount - sectionCount);
|
||||||
NSIndexSet *sections = [NSIndexSet indexSetWithIndexesInRange:range];
|
NSIndexSet *sections = [NSIndexSet indexSetWithIndexesInRange:range];
|
||||||
[super insertSections:sections withRowAnimation:UITableViewRowAnimationAutomatic];
|
[super insertSections:sections withRowAnimation:UITableViewRowAnimationNone];
|
||||||
}
|
}
|
||||||
|
|
||||||
[super insertRowsAtIndexPaths:indexPaths withRowAnimation:UITableViewRowAnimationAutomatic];
|
[super insertRowsAtIndexPaths:indexPaths withRowAnimation:UITableViewRowAnimationNone];
|
||||||
|
|
||||||
[super endUpdates];
|
[super endUpdates];
|
||||||
}
|
}
|
||||||
|
|||||||
@ -65,6 +65,22 @@ typedef NS_ENUM(NSInteger, ASScrollDirection) {
|
|||||||
return self;
|
return self;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
- (void)dealloc
|
||||||
|
{
|
||||||
|
[self teardownAllNodes];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)teardownAllNodes
|
||||||
|
{
|
||||||
|
for (ASCellNode *node in _nodes.allValues) {
|
||||||
|
[node removeFromSupernode];
|
||||||
|
[node.view removeFromSuperview];
|
||||||
|
}
|
||||||
|
[_nodes removeAllObjects];
|
||||||
|
_nodes = nil;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
+ (dispatch_queue_t)sizingQueue
|
+ (dispatch_queue_t)sizingQueue
|
||||||
{
|
{
|
||||||
static dispatch_queue_t sizingQueue = NULL;
|
static dispatch_queue_t sizingQueue = NULL;
|
||||||
@ -255,16 +271,7 @@ static BOOL ASRangeIsValid(NSRange range)
|
|||||||
/*
|
/*
|
||||||
* teardown
|
* teardown
|
||||||
*/
|
*/
|
||||||
for (ASCellNode *node in _nodes.objectEnumerator) {
|
[self teardownAllNodes];
|
||||||
[node removeFromSupernode];
|
|
||||||
[node.view removeFromSuperview];
|
|
||||||
}
|
|
||||||
[_nodes removeAllObjects];
|
|
||||||
_nodes = nil;
|
|
||||||
|
|
||||||
for (UIView *view in [[ASRangeController workingView] subviews]) {
|
|
||||||
[view removeFromSuperview];
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* setup
|
* setup
|
||||||
|
|||||||
@ -23,7 +23,9 @@
|
|||||||
#if ASDISPLAYNODE_DELAY_DISPLAY
|
#if ASDISPLAYNODE_DELAY_DISPLAY
|
||||||
static long __ASDisplayLayerMaxConcurrentDisplayCount = 1;
|
static long __ASDisplayLayerMaxConcurrentDisplayCount = 1;
|
||||||
#else
|
#else
|
||||||
static long __ASDisplayLayerMaxConcurrentDisplayCount = 1024; // essentially no limit until we determine a good value.
|
// Basing this off of CPU core count would make sense, but first some experimentation should be done to understand
|
||||||
|
// if having more ready-to-run work keeps the CPU clock up (or other interesting scheduler effects).
|
||||||
|
static long __ASDisplayLayerMaxConcurrentDisplayCount = 8;
|
||||||
#endif
|
#endif
|
||||||
static dispatch_semaphore_t __ASDisplayLayerConcurrentDisplaySemaphore;
|
static dispatch_semaphore_t __ASDisplayLayerConcurrentDisplaySemaphore;
|
||||||
|
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user