mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-08-17 19:09:56 +00:00
ASDisplayNode and several subclasses had previously cleared memory-heavy objects like the backing store and text layout manager when the node's view or layer is removed from a visible heirarchy. This works great in any system that uses a "working range", where exiting the range removes the node from the hierarchy and reclaiming memory at that time is important. However, for standard UIViewController patterns (unused in Paper), this behavior causes highly undesirable thrashing (leading to visible flashes & wasteful re-rendering of content). After this change, node subclasses should implement -reclaimMemory if they need to perform any other cleanup besides backing store destruction when they leave a working range or other scenario where memory reduction is valuable. To trigger this behavior, calling code should use -recursivelyReclaimMemory. r=nadi
301 lines
10 KiB
Objective-C
301 lines
10 KiB
Objective-C
/* Copyright (c) 2014-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 <pthread.h>
|
|
|
|
#import <AsyncDisplayKit/_ASDisplayLayer.h>
|
|
#import <AsyncDisplayKit/ASAssert.h>
|
|
#import <AsyncDisplayKit/ASDisplayNode.h>
|
|
#import <AsyncDisplayKit/ASThread.h>
|
|
|
|
|
|
/**
|
|
* The subclass header _ASDisplayNode+Subclasses_ defines the following methods that either must or can be overriden by
|
|
* subclasses of ASDisplayNode.
|
|
*
|
|
* These methods should never be called directly by other classes.
|
|
*
|
|
* ## Drawing
|
|
*
|
|
* Implement one of +displayAsyncLayer:parameters:isCancelled: or +drawRect:withParameters:isCancelled: to provide
|
|
* drawing for your node.
|
|
*
|
|
* Use -drawParametersForAsyncLayer: to copy any properties that are involved in drawing into an immutable object for
|
|
* use on the display queue. The display and drawRect implementations *MUST* be thread-safe, as they can be called on
|
|
* the displayQueue (asynchronously) or the main thread (synchronously/displayImmediately).
|
|
*
|
|
* Class methods that require passing in copies of the values are used to minimize the need for locking around instance
|
|
* variable access, and the possibility of the asynchronous display pass grabbing an inconsistent state across multiple
|
|
* variables.
|
|
*/
|
|
|
|
@interface ASDisplayNode (ASDisplayNodeSubclasses)
|
|
|
|
|
|
/** @name View Configuration */
|
|
|
|
|
|
/**
|
|
* @return The view class to use when creating a new display node instance. Defaults to _ASDisplayView.
|
|
*/
|
|
+ (Class)viewClass;
|
|
|
|
|
|
/** @name Properties */
|
|
|
|
|
|
/**
|
|
* @abstract The scale factor to apply to the rendering.
|
|
*
|
|
* @discussion Use setNeedsDisplayAtScale: to set a value and then after display, the display node will set the layer's
|
|
* contentsScale. This is to prevent jumps when re-rasterizing at a different contentsScale.
|
|
* Read this property if you need to know the future contentsScale of your layer, eg in drawParameters.
|
|
*
|
|
* @see setNeedsDisplayAtScale:
|
|
*/
|
|
@property (nonatomic, assign, readonly) CGFloat contentsScaleForDisplay;
|
|
|
|
/**
|
|
* @abstract Whether the view or layer of this display node is currently in a window
|
|
*/
|
|
@property (nonatomic, readonly, assign, getter=isInWindow) BOOL inWindow;
|
|
|
|
|
|
/** @name View Lifecycle */
|
|
|
|
|
|
/**
|
|
* @abstract Called on the main thread immediately after self.view is created.
|
|
*
|
|
* @discussion This is the best time to add gesture recognizers to the view.
|
|
*/
|
|
- (void)didLoad;
|
|
|
|
|
|
/** @name Layout */
|
|
|
|
|
|
/**
|
|
* @abstract Called on the main thread by the view's -layoutSubviews.
|
|
*
|
|
* @discussion Subclasses override this method to layout all subnodes or subviews.
|
|
*/
|
|
- (void)layout;
|
|
|
|
/**
|
|
* @abstract Called on the main thread by the view's -layoutSubviews, after -layout.
|
|
*
|
|
* @discussion Gives a chance for subclasses to perform actions after the subclass and superclass have finished laying
|
|
* out.
|
|
*/
|
|
- (void)layoutDidFinish;
|
|
|
|
|
|
/** @name Sizing */
|
|
|
|
|
|
/**
|
|
* @abstract Return the calculated size.
|
|
*
|
|
* @discussion Subclasses that override should expect this method to be called on a non-main thread. The returned size
|
|
* is cached by ASDisplayNode for quick access during -layout, via -calculatedSize. Other expensive work that needs to
|
|
* be done before display can be performed here, and using ivars to cache any valuable intermediate results is
|
|
* encouraged.
|
|
*
|
|
* @note This method should not be called directly outside of ASDisplayNode; use -measure: or -calculatedSize instead.
|
|
*/
|
|
- (CGSize)calculateSizeThatFits:(CGSize)constrainedSize;
|
|
|
|
/**
|
|
* @abstract Invalidate previously measured and cached size.
|
|
*
|
|
* @discussion Subclasses should call this method to invalidate the previously measured and cached size for the display
|
|
* node, when the contents of the node change in such a way as to require measuring it again.
|
|
*/
|
|
- (void)invalidateCalculatedSize;
|
|
|
|
|
|
/** @name Drawing */
|
|
|
|
|
|
/**
|
|
* @summary Delegate method to draw layer contents into a CGBitmapContext. The current UIGraphics context will be set
|
|
* to an appropriate context.
|
|
*
|
|
* @param parameters An object describing all of the properties you need to draw. Return this from
|
|
* -drawParametersForAsyncLayer:
|
|
* @param isCancelled Execute this block to check whether the current drawing operation has been cancelled to avoid
|
|
* unnecessary work. A return value of YES means cancel drawing and return.
|
|
* @param isRasterizing YES if the layer is being rasterized into another layer, in which case drawRect: probably wants
|
|
* to avoid doing things like filling its bounds with a zero-alpha color to clear the backing store.
|
|
*
|
|
* @note Called on the display queue and/or main queue (MUST BE THREAD SAFE)
|
|
*/
|
|
+ (void)drawRect:(CGRect)bounds
|
|
withParameters:(id<NSObject>)parameters
|
|
isCancelled:(asdisplaynode_iscancelled_block_t)isCancelledBlock
|
|
isRasterizing:(BOOL)isRasterizing;
|
|
|
|
/**
|
|
* @summary Delegate override to provide new layer contents as a UIImage.
|
|
*
|
|
* @param parameters An object describing all of the properties you need to draw. Return this from
|
|
* -drawParametersForAsyncLayer:
|
|
* @param isCancelled Execute this block to check whether the current drawing operation has been cancelled to avoid
|
|
* unnecessary work. A return value of YES means cancel drawing and return.
|
|
*
|
|
* @return A UIImage with contents that are ready to display on the main thread. Make sure that the image is already
|
|
* decoded before returning it here.
|
|
*
|
|
* @note Called on the display queue and/or main queue (MUST BE THREAD SAFE)
|
|
*/
|
|
+ (UIImage *)displayWithParameters:(id<NSObject>)parameters
|
|
isCancelled:(asdisplaynode_iscancelled_block_t)isCancelledBlock;
|
|
|
|
/**
|
|
* @abstract Delegate override for drawParameters
|
|
*
|
|
* @note Called on the main thread only
|
|
*/
|
|
- (NSObject *)drawParametersForAsyncLayer:(_ASDisplayLayer *)layer;
|
|
|
|
/**
|
|
* @abstract Indicates that the receiver has finished displaying.
|
|
*
|
|
* @discussion Subclasses may override this method to be notified when display (asynchronous or synchronous) has
|
|
* completed.
|
|
*/
|
|
- (void)displayDidFinish;
|
|
|
|
|
|
/**
|
|
* @abstract Marks the receiver's bounds as needing to be redrawn, with a scale value.
|
|
*
|
|
* @discussion Subclasses should override this if they don't want their contentsScale changed.
|
|
*
|
|
* @note This changes an internal property.
|
|
* -setNeedsDisplay is also available to trigger display without changing contentsScaleForDisplay.
|
|
* @see contentsScaleForDisplay
|
|
*/
|
|
- (void)setNeedsDisplayAtScale:(CGFloat)contentsScale;
|
|
|
|
/**
|
|
* @abstract Recursively calls setNeedsDisplayAtScale: on subnodes.
|
|
*
|
|
* @discussion Subclasses may override this if they require modifying the scale set on their child nodes.
|
|
*
|
|
* @note Only the node tree is walked, not the view or layer trees.
|
|
*
|
|
* @see setNeedsDisplayAtScale:
|
|
* @see contentsScaleForDisplay
|
|
*/
|
|
- (void)recursivelySetNeedsDisplayAtScale:(CGFloat)contentsScale;
|
|
|
|
|
|
/** @name Touch handling */
|
|
|
|
|
|
/**
|
|
* @abstract Tells the node when touches began in its view.
|
|
*
|
|
* @param touches A set of UITouch instances.
|
|
* @param event A UIEvent associated with the touch.
|
|
*/
|
|
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event;
|
|
|
|
/**
|
|
* @abstract Tells the node when touches moved in its view.
|
|
*
|
|
* @param touches A set of UITouch instances.
|
|
* @param event A UIEvent associated with the touch.
|
|
*/
|
|
- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event;
|
|
|
|
/**
|
|
* @abstract Tells the node when touches ended in its view.
|
|
*
|
|
* @param touches A set of UITouch instances.
|
|
* @param event A UIEvent associated with the touch.
|
|
*/
|
|
- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event;
|
|
|
|
/**
|
|
* @abstract Tells the node when touches was cancelled in its view.
|
|
*
|
|
* @param touches A set of UITouch instances.
|
|
* @param event A UIEvent associated with the touch.
|
|
*/
|
|
- (void)touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event;
|
|
|
|
|
|
/** @name Managing Gesture Recognizers */
|
|
|
|
|
|
/**
|
|
* @abstract Asks the node if a gesture recognizer should continue tracking touches.
|
|
*
|
|
* @param gestureRecognizer A gesture recognizer trying to recognize a gesture.
|
|
*/
|
|
- (BOOL)gestureRecognizerShouldBegin:(UIGestureRecognizer *)gestureRecognizer;
|
|
|
|
|
|
/** @name Hit Testing */
|
|
|
|
|
|
/**
|
|
* @abstract Returns the view that contains the point.
|
|
*
|
|
* @discussion Override to make this node respond differently to touches: (e.g. hide touches from subviews, send all
|
|
* touches to certain subviews (hit area maximizing), etc.)
|
|
*
|
|
* @param point A point specified in the node's local coordinate system (bounds).
|
|
* @param event The event that warranted a call to this method.
|
|
*
|
|
* @return Returns a UIView, not ASDisplayNode, for two reasons:
|
|
* 1) allows sending events to plain UIViews that don't have attached nodes,
|
|
* 2) hitTest: is never called before the views are created.
|
|
*/
|
|
- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event;
|
|
|
|
|
|
/** @name Observing node-related changes */
|
|
|
|
|
|
// Called just before the view is added to a superview.
|
|
- (void)willEnterHierarchy;
|
|
|
|
// Called after the view is removed from the window.
|
|
- (void)didExitHierarchy;
|
|
|
|
// Called by -recursivelyReclaimMemory. Provides an opportunity to clear backing store and other memory-intensive intermediates,
|
|
// such as text layout managers or downloaded content that can be written to a disk cache.
|
|
// Base class implements self.contents = nil, clearing any backing store, for asynchronous regeneration when needed.
|
|
- (void)reclaimMemory;
|
|
|
|
|
|
/** @name Description */
|
|
|
|
|
|
/**
|
|
* @abstract Return a description of the node
|
|
*
|
|
* @discussion The function that gets called for each display node in -recursiveDescription
|
|
*/
|
|
- (NSString *)descriptionForRecursiveDescription;
|
|
|
|
@end
|
|
|
|
@interface ASDisplayNode (ASDisplayNodePrivate)
|
|
// This method has proven helpful in a few rare scenarios, similar to a category extension on UIView,
|
|
// but it's considered private API for now and its use should not be encouraged.
|
|
- (ASDisplayNode *)_supernodeWithClass:(Class)supernodeClass;
|
|
@end
|
|
|
|
#define ASDisplayNodeAssertThreadAffinity(viewNode) ASDisplayNodeAssert(!viewNode || ASDisplayNodeThreadIsMain() || !(viewNode).nodeLoaded, @"Incorrect display node thread affinity")
|
|
#define ASDisplayNodeCAssertThreadAffinity(viewNode) ASDisplayNodeCAssert(!viewNode || ASDisplayNodeThreadIsMain() || !(viewNode).nodeLoaded, @"Incorrect display node thread affinity")
|