facebookarchive / asyncdisplaykit Goto Github PK
View Code? Open in Web Editor NEWSmooth asynchronous user interfaces for iOS apps.
Home Page: http://asyncdisplaykit.org
License: Other
Smooth asynchronous user interfaces for iOS apps.
Home Page: http://asyncdisplaykit.org
License: Other
I am including AsyncDisplayKit as static library in my project, but in order to import the headers in this way: #import <AsyncDisplayKit/AsyncDisplayKit.h>
, the public headers folder path of the AsyncDisplayKit static library target needs to be changed to: include/$(TARGET_NAME)
. It would be great if you could update this in the next release.
I have an ASTableView nested in a view controller a few levels deep in a UINavigationController stack. If the user dismisses the controller with the table while the table is performing asynchronous layout operations, the app occasionally crashes.
More specifically, crashes seem to occur in sizeNextBlock
when nodeForIndexPath
is called.
To circumvent this, I've implemented my data source with conditionals to validate the view's state and data.
func tableView(tableView: ASTableView!, nodeForRowAtIndexPath indexPath: NSIndexPath!) -> ASCellNode! {
let cell = MyCell()
if !self.isBeingDismissed() && indexPath.row < self.dataModel.count {
cell.myObject = self.dataModel[indexPath.row]
}
return cell
}
Checking self.isBeingDismissed()
seemed to account for most of the crashes. Adding the indexPath.row < self.dataModel.count
seems to cover a few more race scenarios.
Is this a bug with ASTableView or am I using it incorrectly?
Seems like there are some failing tests on Xcode 6 beta (iOS 8 beta).
testSpaceBoundingBoxForNoWordKerning
and testSpaceBoundingBoxForWordKerning
fail because of bounding box's width, which returns different results on Xcode 5/iOS 7.1 (value = 4.0) and Xcode 6/iOS 8 (value = 3.55200005...). I'm assuming kerning returns different widths because the system font was slightly tweaked in iOS 8. Not sure how to fix this for both versions while still testing expected behavior.
testAttributeCleansing
fails because apparently the expected and actual cleansed strings don't match, but from all the visible properties they are the same strings. So it might be the way NSAttributedString
uses its isEqualToAttributedString:
in iOS 8.
Sorry for not being too helpful, just wanted to keep an eye on these because it might mean Apple introduces slight changes in behaviour in text rendering that actually provide different values.
i am trying to add nodes at the start of the table view using appendNodesWithIndexPaths but it appends nodes at the end which leaves my table view in an inconsistent data. So is it possible to append nodes at the start using this method ,if not what are my options except reloading the entire table view?
The naming of
- (CGSize)sizeToFit:(CGSize)constrainedSize;
in ASDisplayNode
is really confusing. UIView
uses the exact same method name with void
return type to actually resize the view, and sizeThatFits:
for only computing the size. I think renaming the ASDisplayNode
method to
- (CGSize)sizeThatFits:(CGSize)constrainedSize;
would make a lot of sense.
PS. The comment in ASDisplayNode.h
already mentions it as a TODO.
- (void)textNode:(ASTextNode *)textNode tappedLinkAttribute:(NSString *)attribute value:(id)value atPoint:(CGPoint)point textRange:(NSRange)textRange
{
if (_linkClickedBlock) {
if ([value isKindOfClass:[NSURL class]]) {
_linkClickedBlock((NSURL *)value);
return;
} else if ([value isKindOfClass:[NSString class]]) {
NSURL *url = [NSURL URLWithString:value];
_linkClickedBlock(url);
}
}
}
- (BOOL)textNode:(ASTextNode *)textNode shouldHighlightLinkAttribute:(NSString *)attribute value:(id)value
{
return NO;
// Test with:
// return [attribute isEqualToString:NSLinkAttributeName];
}
Text node is configured as such (code from just before NSLink
was made a default link attribute):
ASTextNode *textNode = [[ASTextNode alloc] init];
textNode.delegate = self;
textNode.linkAttributeNames = @[NSLinkAttributeName];
textNode.opaque = YES;
textNode.userInteractionEnabled = YES;
Breakpoint configured for the first delegate method is never hit unless the link is also highlight-able.
This is probably a blocker for me to start making use of it at work. For a feed, appending is sufficient, but for something as simple as reordering cells according to a different sort, having to trash the nodes is kind of a no-go.
I downloaded the zip, and ran pod install
in the Kittens sample directory. This error is thrown every few runs...
2014-10-20 11:37:46.437 Sample[18223:842005] *** Assertion failure in -[ASImageNode setImage:], /Users/n/Desktop/AsyncDisplayKit-master/AsyncDisplayKit/ASImageNode.mm:108
2014-10-20 11:37:46.437 Sample[18223:842008] *** Assertion failure in -[ASImageNode setImage:], /Users/n/Desktop/AsyncDisplayKit-master/AsyncDisplayKit/ASImageNode.mm:108
2014-10-20 11:37:46.437 Sample[18223:842014] *** Assertion failure in -[ASImageNode setImage:], /Users/n/Desktop/AsyncDisplayKit-master/AsyncDisplayKit/ASImageNode.mm:108
2014-10-20 11:37:46.445 Sample[18223:842008] *** Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'Incorrect display node thread affinity'
*** First throw call stack:
(
0 CoreFoundation 0x000000010b539f35 __exceptionPreprocess + 165
1 libobjc.A.dylib 0x000000010b1d2bb7 objc_exception_throw + 45
2 CoreFoundation 0x000000010b539d9a +[NSException raise:format:arguments:] + 106
3 Foundation 0x000000010adef5df -[NSAssertionHandler handleFailureInMethod:object:file:lineNumber:description:] + 195
4 Sample 0x000000010ab40f73 -[ASImageNode setImage:] + 323
5 Sample 0x000000010ab0bc8f __25-[KittenNode fetchKitten]_block_invoke + 591
6 CFNetwork 0x000000010de31935 __67+[NSURLConnection sendAsynchronousRequest:queue:completionHandler:]_block_invoke_2 + 155
7 Foundation 0x000000010ae1301f __NSBLOCKOPERATION_IS_CALLING_OUT_TO_A_BLOCK__ + 7
8 Foundation 0x000000010ad52db2 -[NSBlockOperation main] + 98
9 Foundation 0x000000010ad35384 -[__NSOperationInternal _start:] + 645
10 Foundation 0x000000010ad34f93 __NSOQSchedule_f + 184
11 libdispatch.dylib 0x000000010d3e37f4 _dispatch_client_callout + 8
12 libdispatch.dylib 0x000000010d3cbb22 _dispatch_queue_drain + 1417
13 libdispatch.dylib 0x000000010d3cb432 _dispatch_queue_invoke + 235
14 libdispatch.dylib 0x000000010d3cdfc1 _dispatch_root_queue_drain + 685
15 libdispatch.dylib 0x000000010d3cf5d9 _dispatch_worker_thread3 + 111
16 libsystem_pthread.dylib 0x000000010d7676cb _pthread_wqthread + 729
17 libsystem_pthread.dylib 0x000000010d7654a1 start_wqthread + 13
)
2014-10-20 11:37:46.445 Sample[18223:842014] *** Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'Incorrect display node thread affinity'
*** First throw call stack:
(
0 CoreFoundation 0x000000010b539f35 __exceptionPreprocess + 165
1 libobjc.A.dylib 0x000000010b1d2bb7 objc_exception_throw + 45
2 CoreFoundation 0x000000010b539d9a +[NSException raise:format:arguments:] + 106
3 Foundation 0x000000010adef5df -[NSAssertionHandler handleFailureInMethod:object:file:lineNumber:description:] + 195
4 Sample 0x000000010ab40f73 -[ASImageNode setImage:] + 323
5 Sample 0x000000010ab0bc8f __25-[KittenNode fetchKitten]_block_invoke + 591
6 CFNetwork 0x000000010de31935 __67+[NSURLConnection sendAsynchronousRequest:queue:completionHandler:]_block_invoke_2 + 155
7 Foundation 0x000000010ae1301f __NSBLOCKOPERATION_IS_CALLING_OUT_TO_A_BLOCK__ + 7
8 Foundation 0x000000010ad52db2 -[NSBlockOperation main] + 98
9 Foundation 0x000000010ad35384 -[__NSOperationInternal _start:] + 645
10 Foundation 0x000000010ad34f93 __NSOQSchedule_f + 184
11 libdispatch.dylib 0x000000010d3e37f4 _dispatch_client_callout + 8
12 libdispatch.dylib 0x000000010d3cbb22 _dispatch_queue_drain + 1417
13 libdispatch.dylib 0x000000010d3cb432 _dispatch_queue_invoke + 235
14 libdispatch.dylib 0x000000010d3cdfc1 _dispatch_root_queue_drain + 685
15 libdispatch.dylib 0x000000010d3cf5d9 _dispatch_worker_thread3 + 111
16 libsystem_pthread.dylib 0x000000010d7676cb _pthread_wqthread + 729
17 libsystem_pthread.dylib 0x000000010d7654a1 start_wqthread + 13
)
libc++abi.dylib: terminating with uncaught exception of type NSException2014-10-20 11:37:46.445 Sample[18223:842005] *** Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'Incorrect display node thread affinity'
*** First throw call stack:
(
0 CoreFoundation 0x000000010b539f35 __exceptionPreprocess + 165
1 libobjc.A.dylib 0x000000010b1d2bb7 objc_exception_throw + 45
2 CoreFoundation 0x000000010b539d9a +[NSException raise:format:arguments:] + 106
3 Foundation 0x000000010adef5df -[NSAssertionHandler handleFailureInMethod:object:file:lineNumber:description:] + 195
4 Sample 0x000000010ab40f73 -[ASImageNode setImage:] + 323
5 Sample 0x000000010ab0bc8f __25-[KittenNode fetchKitten]_block_invoke + 591
6 CFNetwork 0x000000010de31935 __67+[NSURLConnection sendAsynchronousRequest:queue:completionHandler:]_block_invoke_2 + 155
7 Foundation 0x000000010ae1301f __NSBLOCKOPERATION_IS_CALLING_OUT_TO_A_BLOCK__ + 7
8 Foundation 0x000000010ad52db2 -[NSBlockOperation main] + 98
9 Foundation 0x000000010ad35384 -[__NSOperationInternal _start:] + 645
10 Foundation 0x000000010ad34f93 __NSOQSchedule_f + 184
11 libdispatch.dylib 0x000000010d3e37f4 _dispatch_client_callout + 8
12 libdispatch.dylib 0x000000010d3cbb22 _dispatch_queue_drain + 1417
13 libdispatch.dylib 0x000000010d3cb432 _dispatch_queue_invoke + 235
14 libdispatch.dylib 0x000000010d3cdfc1 _dispatch_root_queue_drain + 685
15 libdispatch.dylib 0x000000010d3cf5d9 _dispatch_worker_thread3 + 111
16 libsystem_pthread.dylib 0x000000010d7676cb _pthread_wqthread + 729
17 libsystem_pthread.dylib 0x000000010d7654a1 start_wqthread + 13
)
libc++abi.dylib:
terminating with uncaught exception of type NSExceptionlibc++abi.dylib:
Setting "layerBacked" value to YES is recommended for performance, but I've found that in certain situations it causes ASDisplayNodes to flicker and perform additional (and unnecessary) drawing.
Here you can see flickering when presenting and dismissing view controller:
Only difference between two nodes is layerBacked property set to YES on right one.
I'm using long emoji string to make drawing more expensive so flickering effect is visible on simulator. On devices effect can be observed also with strings that are much less expensive to draw.
Same effect and can be observed with ASImageNode.
I can provide example project if necessary.
We should check if node is loaded in the cycle. Otherwise node.view might load view.
- (void)teardownAllNodes
{
for (ASCellNode *node in _nodes.allValues) {
[node removeFromSupernode];
[node.view removeFromSuperview];
}
[_nodes removeAllObjects];
_nodes = nil;
}
I was under the impression that #30 fixed this issue, but I'm still seeing the row animation cells sliding down when they're first loaded. I played around with swapping out the animations in -[ASTableView rangeController:didSizeNodesWithIndexPaths:], but it doesn't seem to have an effect for row insertion (section insertion animation type changes are reflected, however).
It crashes with nil-node in block:
for (NSIndexPath *indexPath in indexPaths) {
ASCellNode *node = [_delegate rangeController:self nodeForIndexPath:indexPath];
node.asyncdisplaykit_indexPath = indexPath;
_nodes[indexPath] = node;
}
Assert occurs with zero constrained size in block:
dispatch_group_async(group, [ASRangeController sizingQueue], ^{
[node measure:[_delegate rangeController:self constrainedSizeForNodeAtIndexPath:indexPath]];
node.frame = CGRectMake(0.0f, 0.0f, node.calculatedSize.width, node.calculatedSize.height);
});
The ability to updating rows is important when changing cell's height, otherwise we need to call - reloadData
on ASTableView. But it's documented that - reloadData
will "destroying the working range and all cached nodes", which is quite expensive.
ASDisplayNode+Subclasses.h
references these methods…
// Subclasses should implement -display if the layer's contents will be set directly to an arbitrary buffer (e.g. decoded JPEG).
// Called on a background thread, some time after the view has been created. This method is called if -drawInContext: is not implemented.
- (void)display;
// Subclasses should implement if a backing store / context is desired. Called on a background thread, some time after the view has been created.
- (void)drawInContext:(CGContextRef)ctx;
…but they're actually no longer used. Update this header to reference the current mechanism from _ASDisplayLayer.h
:
// Called on the display queue and/or main queue (MUST BE THREAD SAFE)
/**
@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.
*/
+ (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.
*/
+ (UIImage *)displayWithParameters:(id<NSObject>)parameters isCancelled:(asdisplaynode_iscancelled_block_t)isCancelledBlock;
// Called on the main thread only
/**
@summary Delegate override for drawParameters
*/
- (NSObject *)drawParametersForAsyncLayer:(_ASDisplayLayer *)layer;
Is there a similar API to the deleteSections:
API in UITableView
? Further, How does one interface with beginUpdates
and endUpdates
with Core Data?
appledoc
can't generate complete docs for ASImageNode — fix its headers.
A lot of boolean properties don't follow Apple's naming conventions while a lot of others do. For example, in ASDisplayNode.h, there are a few boolean properties that look like this:
@property (nonatomic, readonly) BOOL isSynchronous;
Whereas in ASControlNode.h, all the properties follow the named getter convention:
@property (nonatomic, readwrite, assign, getter=isEnabled) BOOL enabled
Just wanted to point this out.
i.e. for copy-paste support on text nodes.
Trying to funnel - (BOOL)canPerformAction:(SEL)action withSender:(id)sender
from _ASDisplayView to the node didn't seem to work.
In the same way that ASTableView is a UITableView subclass that integrates node-based cells and a working range, a UICollectionView subclass that benefits form the advances made by ASDK would be fantastic.
Quote from Apple docs:
NSRegularExpression is designed to be immutable and thread safe, so that a single instance can be used in matching operations on multiple threads at once.
UITextView property signature:
@property(nonatomic) UIDataDetectorTypes dataDetectorTypes
NSDataDetector factory method signature:
+ (NSDataDetector *)dataDetectorWithTypes:(NSTextCheckingTypes)checkingTypes error:(NSError **)error;
NSDataDetector's supported NSTextCheckingTypes
:
NSTextCheckingTypeDate, NSTextCheckingTypeAddress, NSTextCheckingTypeLink, NSTextCheckingTypePhoneNumber, and NSTextCheckingTypeTransitInformation
UITextView
's accepted UIDataDetectorType
:
UIDataDetectorTypePhoneNumber = 1 << 0,
UIDataDetectorTypeLink = 1 << 1,
UIDataDetectorTypeAddress = 1 << 2,
UIDataDetectorTypeCalendarEvent = 1 << 3,
UIDataDetectorTypeNone = 0,
UIDataDetectorTypeAll = NSUIntegerMax
So basically, a very close correspondence in API. Seems like a pretty manageable add-in.
It's possible to use AsyncDisplayKit with MKOverlayRenderer (MKPolygon or MKPolyline)?
It might be awesome!
My understanding is that on every ASImageNode redraw, provided image is decoded and scaled in background context. This is unnecessary work for bundled images (like UI elements, icons, backgrounds etc.) which should already be provided in exactly same size as displayed in interface, and if image is loaded using imageNamed:, decoded image is cached by UIKit (decoding is done only once per image).
Using AsyncDisplayKit, if such image is used in many instances of ASImageNode, same work for scaling and decoding will be done each time any of these nodes redraws. This causes delay before UI element can be displayed.
What is more, images can be correctly decoded and sized even if they are downloaded from web. I'm using Path's FastImageCache https://github.com/path/FastImageCache for image caching. One of great features of FIC is background image sizing and decoding. Other frameworks and caching systems also often incorporate such functionality.
This issue is especially visible in UITableView cells, where same UI images are unnecessarily decoded and sized for nodes in every cell. Issue #37 causes even more additional image redraws.
Adding property to ASImageNode which would skip sizing and decoding should improve performance if image is already decoded and sized. Another solution could be caching of decoded images.
What are your thoughts on this issue?
Hey guys, I've recently implemented AsyncDisplayKit into a side-project i'm working on and its been amazing so far. One thing I'm confused about is the ASTextNode URL highlighting. Based on the API I thought it would have been there by default (for example ASTextNodeHighlightStyle
). Is this not the case?
I did some digging and eventually found the problem was that no sublayer had as_allowsHighlightDrawing
enabled on it, and with some more digging noticed that it isn't set anywhere even privately (unless I missed something).
I tried calling as_setAllowsHighlightDrawing
on a ASTextNode layer itself just to see what would happen but the highlight overlay gets clipped because the text frame hasn't been adjusted.
Is this something coming in the future? Can I do anything to help bring it to light? Thanks!
ASDisplayNode.mm:
- (id)initWithViewClass:(Class)viewClass
{
if (!(self = [self init]))
return nil;
...
@implementation FooBarViewNode
- (instancetype)init // calls itself, resulting in crash due to stack overflow
//- (instancetype)init2 // doesn't
{
if (self = [super initWithViewClass:[UIView class]]) {
...
Suggested solution:
Don't use a bar - (id)init
as the designated initializer.
- (instancetype)initWithViewClass:(Class)viewClass layerClass:(Class)layerClass
Introduce that to ASDisplayNode+Subclasses.h. Assert that at least one of those parameters are nil, and forward - (id)initWithViewClass:(Class)viewClass
, - (id)initWithLayerClass:(Class)layerClass
and - (id)init
to that.
How can I make WKWebView behave asynchronously as long as there is no ASWKWebView equivalent?
Is https://github.com/facebook/AsyncDisplayKit/blob/master/AsyncDisplayKit/Private/ASDisplayNode%2BAsyncDisplay.mm#L26 used for anything? I believe it just complicates the async display process and we should probably remove it.
Once appledoc
runs with zero warnings, add it as a Travis CI build step to ensure no documentation regressions.
I often handle assertion in -[ASTextNode setAttributedString] at line [self invalidateCalculatedSize].
I use next check to decide, if I should set text on mainThread:
if (textNode.isNodeLoaded && [NSThread isMainThread] == NO) {
dispatch_async(dispatch_get_main_queue(), ^{
textNode.attributedString = text;
});
}
else {
textNode.attributedString = text;
}
But node might be loaded after my check and before execution of line textNode.attributedString = text.
Is there other way to check if I should set attributedString on mainThread?
Is it a bad purpose to set attributedString after node is being loaded?
I found interesting bug when integrating AsyncDisplayKit into my project.
ASControlNode sends action second time if right after receiving first action UIActionSheet is shown. This bug occurs only if it's supernode has gesture recognizer attached and whole node hierarchy is subview of UIScrollView. Analogous setup using UIViews behaves correctly.
It's quite complicated, so just look at this test project: https://github.com/Jercik/ASDK_bug_actions. After tapping on cyan view (which is subclass of ASControlNode) UIActionSheet is shown twice, after tapping on red view (subclass of UIButton) UIActionSheet is shown once.
If UIActionSheet's showInView: is wrapped in dispatch_async problem don't exist.
//workaround:
dispatch_async(dispatch_get_main_queue(), ^{
[actionSheet showInView:self.view];
});
The kitten sample is modified to be a UIPageViewController.
Just like feeds, an extra kitten node is appended after 1 sec in each ASTableView.
When the page controller is swiped, an error occurs.
*** Assertion failure in -[ASRangeController appendNodesWithIndexPaths:], /Users/leo/Projects/AsyncDisplayKit_ASTableView_bug_with_UIPageViewController/Pods/AsyncDisplayKit/AsyncDisplayKit/Details/ASRangeController.mm:598
2014-10-23 13:46:48.037 Sample[10278:21109907] *** Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'invalid argument'
example project: https://github.com/l4u/AsyncDisplayKit_ASTableView_bug_with_UIPageViewController/tree/append_bug
ful log:
https://gist.github.com/l4u/a3bf721107b37af83c4a
In ASRangeController.mm
static BOOL ASRangeIsValid(NSRange range)
{
return range.location != NSNotFound && range.length > 0;
}
This causes an assert from -setVisibleRange:
when you successfully scroll all available index paths offscreen, like so:
This assert seems erroneous as having no visible items is achievable normally.
See my comment on this PR: #75
This is not a critical issue, but it's worth thinking about how it could be improved. The only workaround I can immediately think of is for the ASDK framework to allocate a singleton UIView (on the main thread) simply to read its tintColor property, so that the default value can be set programmatically in that way.
Since shadows & borders are already supported, would be nice to have access to the corner radius property also.
Seems like AsyncDisplayKit only support iOS 7 or later due to dependency of TextKit. It's possible to add support for iOS 6 by rewriting ASTextNode with CoreText?
- (void)appendNodesWithIndexPaths:(NSArray *)indexPaths
doesn't account for _totalNodeCount == 0
, and causes a logic error in -indexPathForIndex:
, where offset == 0
and index == -1
.
Tested by appending nodes to an otherwise empty table view.
'Incorrect display node thread affinity' when ASTableView is used with a UIPageViewController
https://github.com/l4u/AsyncDisplayKit_ASTableView_bug_with_UIPageViewController
To reproduce, swipe for 1 or more pages.
In the NSLondon video, Scott talks about runloop work distribution. Unless I’m missing something here, this optimization does not seem to be implemented right now. I was wondering if you were still planning on adding this feature to the framework.
I understand this strategy applies to expensive operations that have to run on the main thread, such as creating views and adding them to the hierarchy. What about the opposite operations (removing from hierarchy and deallocating views)? Does those benefit from being distributed as well?
#26 introduced an annotation to warn clients that accidentally fail to call superclass implementations of methods that require it.
Although ASDisplayKit is specifically designed to minimize its reliance on superclass method calls that are even possible for the programmer to leave out, there are a few places where they are required (particularly for methods that may be implemented by multiple levels of inheritance in classes created by the framework user).
Let's find the other relevant places to add the annotation.
Preparing to send a pull request to fix some retain cycles in ASDisplayNode and ASTableView.
I don't know whether you guys are planning to keep the non-ARC test classes around. Gotta say I've found them pretty useful to test those memory issues so I'll be adding tests covering these cases.
There is one issue I noticed in ASRangeController that I didn't fix. Nodes are added to a shared workingView
to start rendering but they are not removed from that view when ASRangeController is destroyed. This can cause nodes to stay around indefinitely.
An easy fix would be to copy this teardown code to dealloc
:
for (UIView *view in [[ASRangeController workingView] subviews]) {
[view removeFromSuperview];
}
But since the same workingView
is shared across all ASRangeControllers, I don't know what impact this could have when an app uses many of them at the same time.
My bridging header has the following:
#import <AsyncDisplayKit/AsyncDisplayKit.h>
However, auto-completion for several several critical ASDisplayNode+Subclasses
methods — like didLoad()
, calculateSizeThatFits(_:)
, and layout()
— doesn't work. Adding the following line to my bridging header fixes this:
#import "ASDisplayNode+Subclasses.h"
I'm not sure if this is what you're expecting developers to do, though. I suspect #import <AsyncDisplayKit/AsyncDisplayKit.h>
is meant to expose all public Obj-C headers for AsyncDisplayKit to Swift files.
Looking at the global header, I'm wondering if the issue is that the first two imports are for Objective-C++ headers, and that's why the category doesn't get picked up:
#import <AsyncDisplayKit/ASDisplayNode.h>
#import <AsyncDisplayKit/ASDisplayNodeExtras.h>
I don't have much experience with Obj-C++/Swift interop, so I'm not sure if the answer is as simple as dropping the category imports in the global header. Or if it needs a solution like this one. Or neither, and I'm just missing something obvious. :]
git grep -i cache
shows mentions of caching but no actual logic.
A quick sweep shows that the following is unused:
ASDisplayNode
: NSArray *cachedNodes
ASDisplayNode
: BOOL cacheNode
ASDisplayNode
: ASDisplayNode *superCacheNode
ASImageCacheProtocol
: Unimplemented and unused_ASDisplayView implements a keepalive reference to its node so that it stays alive as long as the view is in the hierarchy. This is what makes the example shown here work, nothing else retains the node.
However, this mechanism is not implemented for layer-backed nodes, and I don't see an easy way to do it. As far as I know, CALayer does not have a direct equivalent to -[UIView willMoveToSuperview:]
. There is the onOrderIn event but it is only sent when the layer enters a visible hierarchy. This is too late in our case.
Since converting to layer-backed nodes is said to be "as simple as" setting a boolean, I guess this limitation should be documented if a solution cannot be found.
Tried updating this for a couple of hours yesterday (10-19). I realized that .transform isn't supported either, in addition to .subnodeTransform.
Technically, this could be seen as a bug when either .transform or .subnodeTransform aren't the identity matrix.
After banging at it for a while, I think that it's the right solution to reorient the methods to recursively call convertPoint/convertRect methods rather than trying to correctly compose arrays.
It's easier to understand and check, and any sane screen dimensions aren't going to be large enough numbers - floats should be accurate to within .5 up to 2^23 , and doubles up to 2^52 (per http://stackoverflow.com/questions/872544/precision-of-floating-point); the built up error from applying, say, seven transforms simply won't going to be that large - and this is for point conversion, not display.
That, or I could continue trying to figure out the right incantations to build the correct transform matrix, this time accounting for .transform and .supernode.subnodeTransform.
Repro project:
http://www.atoulou.se/Repro.tar.bz2
Very barebones. Remember to set zombies to on. Tested using iPhone 5s (7.1) Simulator on OS X 10.9.
Crash 1 (almost every time):
(lldb) thread backtrace
* thread #4: tid = 0x18149, 0x00000001091accc4 CoreFoundation`___forwarding___ + 772, queue = 'com.facebook.AsyncDisplayKit.ASRangeController.sizingQueue', stop reason = EXC_BREAKPOINT (code=EXC_I386_BPT, subcode=0x0)
frame #0: 0x00000001091accc4 CoreFoundation`___forwarding___ + 772
frame #1: 0x00000001091ac938 CoreFoundation`__forwarding_prep_0___ + 120
frame #2: 0x000000010d980ade UIFoundation`-[NSTypesetter _updateParagraphStyleCache:] + 319
frame #3: 0x000000010d981b5c UIFoundation`-[NSTypesetter getLineFragmentRect:usedRect:forParagraphSeparatorGlyphRange:atProposedOrigin:] + 633
frame #4: 0x000000010d98430c UIFoundation`-[NSTypesetter _layoutGlyphsInLayoutManager:startingAtGlyphIndex:maxNumberOfLineFragments:maxCharacterIndex:nextGlyphIndex:nextCharacterIndex:] + 7720
frame #5: 0x000000010d984872 UIFoundation`-[NSTypesetter layoutGlyphsInLayoutManager:startingAtGlyphIndex:maxNumberOfLineFragments:nextGlyphIndex:] + 105
frame #6: 0x000000010d92b6fc UIFoundation`-[NSATSTypesetter layoutGlyphsInLayoutManager:startingAtGlyphIndex:maxNumberOfLineFragments:nextGlyphIndex:] + 460
* frame #7: 0x000000010d94d313 UIFoundation`-[NSLayoutManager insertTextContainer:atIndex:] + 926
frame #8: 0x000000010895250d Repro`-[ASTextNodeRenderer _initializeTextKitComponentsWithAttributedString:](self=0x00007f9259d004f0, _cmd=0x000000010896ba33, attributedString=0x0000000000000000) + 957 at ASTextNodeRenderer.mm:90
frame #9: 0x0000000108952115 Repro`-[ASTextNodeRenderer _initializeTextKitComponentsIfNeeded](self=0x00007f9259d004f0, _cmd=0x000000010896bb70) + 101 at ASTextNodeRenderer.mm:69
frame #10: 0x0000000108952d94 Repro`-[ASTextNodeRenderer size](self=0x00007f9259d004f0, _cmd=0x0000000110e50d67) + 36 at ASTextNodeRenderer.mm:169
frame #11: 0x0000000108947c54 Repro`-[ASTextNode calculateSizeThatFits:](self=0x00007f9259e21a80, _cmd=0x000000010896804b, constrainedSize=CGSize at 0x00000001157ec948) + 2548 at ASTextNode.mm:184
frame #12: 0x000000010891e0c4 Repro`-[ASDisplayNode measure:](self=0x00007f9259e21a80, _cmd=0x0000000108967ff7, constrainedSize=CGSize at 0x00000001157ecab8) + 660 at ASDisplayNode.mm:323
frame #13: 0x0000000108901694 Repro`-[ReproNode calculateSizeThatFits:](self=0x00007f9259e21950, _cmd=0x000000010896804b, constrainedSize=CGSize at 0x00000001157ecb30) + 116 at ReproNode.m:33
frame #14: 0x000000010891e0c4 Repro`-[ASDisplayNode measure:](self=0x00007f9259e21950, _cmd=0x0000000108967ff7, constrainedSize=CGSize at 0x00000001157ecc98) + 660 at ASDisplayNode.mm:323
frame #15: 0x0000000108941fb5 Repro`__34-[ASRangeController sizeNextBlock]_block_invoke_2(.block_descriptor=<unavailable>) + 213 at ASRangeController.mm:538
frame #16: 0x000000010ab6a851 libdispatch.dylib`_dispatch_call_block_and_release + 12
frame #17: 0x000000010ab7d72d libdispatch.dylib`_dispatch_client_callout + 8
frame #18: 0x000000010ab6beab libdispatch.dylib`_dispatch_async_redirect_invoke + 174
frame #19: 0x000000010ab7d72d libdispatch.dylib`_dispatch_client_callout + 8
frame #20: 0x000000010ab6db27 libdispatch.dylib`_dispatch_root_queue_drain + 380
frame #21: 0x000000010ab6dd12 libdispatch.dylib`_dispatch_worker_thread2 + 40
frame #22: 0x000000010af1bef8 libsystem_pthread.dylib`_pthread_wqthread + 314
frame #23: 0x000000010af1efb9 libsystem_pthread.dylib`start_wqthread + 13
(lldb)
Crash 2 (uncommon?):
(lldb) thread backtrace
* thread #4: tid = 0x17667, 0x0000000000000000, queue = 'com.facebook.AsyncDisplayKit.ASRangeController.sizingQueue', stop reason = EXC_BAD_ACCESS (code=1, address=0x0)
frame #0: 0x0000000000000000
frame #1: 0x00000001147cd893 UIFoundation`+[NSTextStorage allocWithZone:] + 33
* frame #2: 0x000000010f7cb219 Repro`-[ASTextNodeRenderer _initializeTextKitComponentsWithAttributedString:](self=0x00007f880d110d50, _cmd=0x000000010f7e4a33, attributedString=0x0000000000000000) + 201 at ASTextNodeRenderer.mm:78
frame #3: 0x000000010f7cb115 Repro`-[ASTextNodeRenderer _initializeTextKitComponentsIfNeeded](self=0x00007f880d110d50, _cmd=0x000000010f7e4b70) + 101 at ASTextNodeRenderer.mm:69
frame #4: 0x000000010f7cbd94 Repro`-[ASTextNodeRenderer size](self=0x00007f880d110d50, _cmd=0x0000000117cb0d67) + 36 at ASTextNodeRenderer.mm:169
frame #5: 0x000000010f7c0c54 Repro`-[ASTextNode calculateSizeThatFits:](self=0x00007f880ad16d70, _cmd=0x000000010f7e104b, constrainedSize=CGSize at 0x000000011c539948) + 2548 at ASTextNode.mm:184
frame #6: 0x000000010f7970c4 Repro`-[ASDisplayNode measure:](self=0x00007f880ad16d70, _cmd=0x000000010f7e0ff7, constrainedSize=CGSize at 0x000000011c539ab8) + 660 at ASDisplayNode.mm:323
frame #7: 0x000000010f77a694 Repro`-[ReproNode calculateSizeThatFits:](self=0x00007f880ad166b0, _cmd=0x000000010f7e104b, constrainedSize=CGSize at 0x000000011c539b30) + 116 at ReproNode.m:33
frame #8: 0x000000010f7970c4 Repro`-[ASDisplayNode measure:](self=0x00007f880ad166b0, _cmd=0x000000010f7e0ff7, constrainedSize=CGSize at 0x000000011c539c98) + 660 at ASDisplayNode.mm:323
frame #9: 0x000000010f7bafb5 Repro`__34-[ASRangeController sizeNextBlock]_block_invoke_2(.block_descriptor=<unavailable>) + 213 at ASRangeController.mm:538
frame #10: 0x00000001119ca851 libdispatch.dylib`_dispatch_call_block_and_release + 12
frame #11: 0x00000001119dd72d libdispatch.dylib`_dispatch_client_callout + 8
frame #12: 0x00000001119cbeab libdispatch.dylib`_dispatch_async_redirect_invoke + 174
frame #13: 0x00000001119dd72d libdispatch.dylib`_dispatch_client_callout + 8
frame #14: 0x00000001119cdb27 libdispatch.dylib`_dispatch_root_queue_drain + 380
frame #15: 0x00000001119cdd12 libdispatch.dylib`_dispatch_worker_thread2 + 40
frame #16: 0x0000000111d72ef8 libsystem_pthread.dylib`_pthread_wqthread + 314
frame #17: 0x0000000111d75fb9 libsystem_pthread.dylib`start_wqthread + 13
(lldb) list
88 _textContainer.lineBreakMode = _truncationMode;
89
90 [_layoutManager addTextContainer:_textContainer];
91
92 [self _invalidateLayout];
93 }
94
95 #pragma mark - Layout Initialization
96
97 - (void)_invalidateLayout
After viewing this, I was wondering if the Components that is mentioned by Ari Grant, is/was using AsyncDisplay, or the idea predates AsyncDisplay altogether.
Just a quick addendum, I mean the use of immutability on the UI.
P.S: This might be wrong place to ask this, if there is a better one, please let me know.
I found two identifiers that were only mentioned in comments but the types themselves aren't defined anywhere:
ASDisplayNodeView
, seems like a protocol that any view usable in a async display node would need to implement, mentioned in _ASPendingState.h:25
.
ASDisplayNodeAsyncView
, seems like a subclass of UIView
that would too be usable in a node (also the way of adding more async views by subclassing), mentioned in ASDisplayNode.h:22
.
Could you please add more details on these types? Plus some sort of a documentation of how to add a custom async view class. Thanks!
_ASAsyncTransactionContainer+Private.h currently resides at Details/Transactions/_ASAsyncTransactionContainer+Private.h. Since the podspec is somewhat coarse in its declarations, this private header is exported.
As far as I can tell from a quick audit, it's the only header file exported that doesn't need to be.
More info on CocoaPods' support to be found here: CocoaPods/CocoaPods#998
Might be bootcamp-able? Unless this is too trivial / not appropriate for that.
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.