Create transfer-array method and use it (#987)

* Create transfer-array method and use it

* License headers

* Update ASArrayByFlatMapping
This commit is contained in:
Adlai Holler 2018-06-29 18:21:55 -07:00 committed by GitHub
parent a4f78ad3e0
commit 77e2d28919
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
15 changed files with 213 additions and 34 deletions

View File

@ -333,6 +333,9 @@
CC224E962066CA6D00BBA57F /* configuration.json in Resources */ = {isa = PBXBuildFile; fileRef = CC224E952066CA6D00BBA57F /* configuration.json */; }; CC224E962066CA6D00BBA57F /* configuration.json in Resources */ = {isa = PBXBuildFile; fileRef = CC224E952066CA6D00BBA57F /* configuration.json */; };
CC2F65EE1E5FFB1600DA57C9 /* ASMutableElementMap.h in Headers */ = {isa = PBXBuildFile; fileRef = CC2F65EC1E5FFB1600DA57C9 /* ASMutableElementMap.h */; }; CC2F65EE1E5FFB1600DA57C9 /* ASMutableElementMap.h in Headers */ = {isa = PBXBuildFile; fileRef = CC2F65EC1E5FFB1600DA57C9 /* ASMutableElementMap.h */; };
CC2F65EF1E5FFB1600DA57C9 /* ASMutableElementMap.m in Sources */ = {isa = PBXBuildFile; fileRef = CC2F65ED1E5FFB1600DA57C9 /* ASMutableElementMap.m */; }; CC2F65EF1E5FFB1600DA57C9 /* ASMutableElementMap.m in Sources */ = {isa = PBXBuildFile; fileRef = CC2F65ED1E5FFB1600DA57C9 /* ASMutableElementMap.m */; };
CC35CEC320DD7F600006448D /* ASCollections.h in Headers */ = {isa = PBXBuildFile; fileRef = CC35CEC120DD7F600006448D /* ASCollections.h */; settings = {ATTRIBUTES = (Public, ); }; };
CC35CEC420DD7F600006448D /* ASCollections.m in Sources */ = {isa = PBXBuildFile; fileRef = CC35CEC220DD7F600006448D /* ASCollections.m */; };
CC35CEC620DD87280006448D /* ASCollectionsTests.m in Sources */ = {isa = PBXBuildFile; fileRef = CC35CEC520DD87280006448D /* ASCollectionsTests.m */; };
CC3B20841C3F76D600798563 /* ASPendingStateController.h in Headers */ = {isa = PBXBuildFile; fileRef = CC3B20811C3F76D600798563 /* ASPendingStateController.h */; settings = {ATTRIBUTES = (Private, ); }; }; CC3B20841C3F76D600798563 /* ASPendingStateController.h in Headers */ = {isa = PBXBuildFile; fileRef = CC3B20811C3F76D600798563 /* ASPendingStateController.h */; settings = {ATTRIBUTES = (Private, ); }; };
CC3B20861C3F76D600798563 /* ASPendingStateController.mm in Sources */ = {isa = PBXBuildFile; fileRef = CC3B20821C3F76D600798563 /* ASPendingStateController.mm */; }; CC3B20861C3F76D600798563 /* ASPendingStateController.mm in Sources */ = {isa = PBXBuildFile; fileRef = CC3B20821C3F76D600798563 /* ASPendingStateController.mm */; };
CC3B208A1C3F7A5400798563 /* ASWeakSet.h in Headers */ = {isa = PBXBuildFile; fileRef = CC3B20871C3F7A5400798563 /* ASWeakSet.h */; settings = {ATTRIBUTES = (Public, ); }; }; CC3B208A1C3F7A5400798563 /* ASWeakSet.h in Headers */ = {isa = PBXBuildFile; fileRef = CC3B20871C3F7A5400798563 /* ASWeakSet.h */; settings = {ATTRIBUTES = (Public, ); }; };
@ -841,6 +844,9 @@
CC2E317F1DAC353700EEE891 /* ASCollectionView+Undeprecated.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "ASCollectionView+Undeprecated.h"; sourceTree = "<group>"; }; CC2E317F1DAC353700EEE891 /* ASCollectionView+Undeprecated.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "ASCollectionView+Undeprecated.h"; sourceTree = "<group>"; };
CC2F65EC1E5FFB1600DA57C9 /* ASMutableElementMap.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ASMutableElementMap.h; sourceTree = "<group>"; }; CC2F65EC1E5FFB1600DA57C9 /* ASMutableElementMap.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ASMutableElementMap.h; sourceTree = "<group>"; };
CC2F65ED1E5FFB1600DA57C9 /* ASMutableElementMap.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ASMutableElementMap.m; sourceTree = "<group>"; }; CC2F65ED1E5FFB1600DA57C9 /* ASMutableElementMap.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ASMutableElementMap.m; sourceTree = "<group>"; };
CC35CEC120DD7F600006448D /* ASCollections.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ASCollections.h; sourceTree = "<group>"; };
CC35CEC220DD7F600006448D /* ASCollections.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = ASCollections.m; sourceTree = "<group>"; };
CC35CEC520DD87280006448D /* ASCollectionsTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = ASCollectionsTests.m; sourceTree = "<group>"; };
CC3B20811C3F76D600798563 /* ASPendingStateController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ASPendingStateController.h; sourceTree = "<group>"; }; CC3B20811C3F76D600798563 /* ASPendingStateController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ASPendingStateController.h; sourceTree = "<group>"; };
CC3B20821C3F76D600798563 /* ASPendingStateController.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = ASPendingStateController.mm; sourceTree = "<group>"; }; CC3B20821C3F76D600798563 /* ASPendingStateController.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = ASPendingStateController.mm; sourceTree = "<group>"; };
CC3B20871C3F7A5400798563 /* ASWeakSet.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ASWeakSet.h; sourceTree = "<group>"; }; CC3B20871C3F7A5400798563 /* ASWeakSet.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ASWeakSet.h; sourceTree = "<group>"; };
@ -1117,6 +1123,8 @@
058D09B1195D04C000B7D73C /* Source */ = { 058D09B1195D04C000B7D73C /* Source */ = {
isa = PBXGroup; isa = PBXGroup;
children = ( children = (
CC35CEC120DD7F600006448D /* ASCollections.h */,
CC35CEC220DD7F600006448D /* ASCollections.m */,
058D0A42195D058D00B7D73C /* Base */, 058D0A42195D058D00B7D73C /* Base */,
CCE04B1D1E313E99006AEBBB /* Collection Data Adapter */, CCE04B1D1E313E99006AEBBB /* Collection Data Adapter */,
DE89C1691DCEB9CC00D49D74 /* Debug */, DE89C1691DCEB9CC00D49D74 /* Debug */,
@ -1241,6 +1249,7 @@
058D09C5195D04C000B7D73C /* Tests */ = { 058D09C5195D04C000B7D73C /* Tests */ = {
isa = PBXGroup; isa = PBXGroup;
children = ( children = (
CC35CEC520DD87280006448D /* ASCollectionsTests.m */,
DBC452DD1C5C6A6A00B16017 /* ArrayDiffingTests.m */, DBC452DD1C5C6A6A00B16017 /* ArrayDiffingTests.m */,
AC026B571BD3F61800BBC17E /* ASAbsoluteLayoutSpecSnapshotTests.m */, AC026B571BD3F61800BBC17E /* ASAbsoluteLayoutSpecSnapshotTests.m */,
696FCB301D6E46050093471E /* ASBackgroundLayoutSpecSnapshotTests.mm */, 696FCB301D6E46050093471E /* ASBackgroundLayoutSpecSnapshotTests.mm */,
@ -2023,6 +2032,7 @@
CCCCCCDB1EC3EF060087FE10 /* ASTextLine.h in Headers */, CCCCCCDB1EC3EF060087FE10 /* ASTextLine.h in Headers */,
9C70F20E1CDBE9E5007D6C76 /* NSArray+Diffing.h in Headers */, 9C70F20E1CDBE9E5007D6C76 /* NSArray+Diffing.h in Headers */,
CCCCCCE71EC3F0FC0087FE10 /* NSAttributedString+ASText.h in Headers */, CCCCCCE71EC3F0FC0087FE10 /* NSAttributedString+ASText.h in Headers */,
CC35CEC320DD7F600006448D /* ASCollections.h in Headers */,
CC7AF196200D9BD500A21BDE /* ASExperimentalFeatures.h in Headers */, CC7AF196200D9BD500A21BDE /* ASExperimentalFeatures.h in Headers */,
CCCCCCDF1EC3EF060087FE10 /* ASTextRunDelegate.h in Headers */, CCCCCCDF1EC3EF060087FE10 /* ASTextRunDelegate.h in Headers */,
9C49C3701B853961000B0DD5 /* ASStackLayoutElement.h in Headers */, 9C49C3701B853961000B0DD5 /* ASStackLayoutElement.h in Headers */,
@ -2304,6 +2314,7 @@
1A6C00111FAB4EDD00D05926 /* ASCornerLayoutSpecSnapshotTests.mm in Sources */, 1A6C00111FAB4EDD00D05926 /* ASCornerLayoutSpecSnapshotTests.mm in Sources */,
254C6B541BF8FF2A003EC431 /* ASTextKitTests.mm in Sources */, 254C6B541BF8FF2A003EC431 /* ASTextKitTests.mm in Sources */,
05EA6FE71AC0966E00E35788 /* ASSnapshotTestCase.m in Sources */, 05EA6FE71AC0966E00E35788 /* ASSnapshotTestCase.m in Sources */,
CC35CEC620DD87280006448D /* ASCollectionsTests.m in Sources */,
ACF6ED631B178DC700DA7C62 /* ASStackLayoutSpecSnapshotTests.mm in Sources */, ACF6ED631B178DC700DA7C62 /* ASStackLayoutSpecSnapshotTests.mm in Sources */,
E52AC9C01FEA916C00AA4040 /* ASRectMapTests.m in Sources */, E52AC9C01FEA916C00AA4040 /* ASRectMapTests.m in Sources */,
CCE4F9BA1F0DBB5000062E4E /* ASLayoutTestNode.mm in Sources */, CCE4F9BA1F0DBB5000062E4E /* ASLayoutTestNode.mm in Sources */,
@ -2448,6 +2459,7 @@
CCA282B51E9EA7310037E8B7 /* ASTipsController.m in Sources */, CCA282B51E9EA7310037E8B7 /* ASTipsController.m in Sources */,
B35062271B010EFD0018CF92 /* ASRangeController.mm in Sources */, B35062271B010EFD0018CF92 /* ASRangeController.mm in Sources */,
0442850A1BAA63FE00D16268 /* ASBatchFetching.m in Sources */, 0442850A1BAA63FE00D16268 /* ASBatchFetching.m in Sources */,
CC35CEC420DD7F600006448D /* ASCollections.m in Sources */,
68FC85E61CE29B9400EDD713 /* ASNavigationController.m in Sources */, 68FC85E61CE29B9400EDD713 /* ASNavigationController.m in Sources */,
CC4C2A791D88E3BF0039ACAB /* ASTraceEvent.m in Sources */, CC4C2A791D88E3BF0039ACAB /* ASTraceEvent.m in Sources */,
34EFC76F1B701CF700AD841F /* ASRatioLayoutSpec.mm in Sources */, 34EFC76F1B701CF700AD841F /* ASRatioLayoutSpec.mm in Sources */,

View File

@ -12,6 +12,7 @@
- Clean up C-function `extern` decorators. [Adlai Holler](https://github.com/Adlai-Holler) - Clean up C-function `extern` decorators. [Adlai Holler](https://github.com/Adlai-Holler)
- Add an experiment to reduce work involved in collection teardown. [Adlai Holler](https://github.com/Adlai-Holler) - Add an experiment to reduce work involved in collection teardown. [Adlai Holler](https://github.com/Adlai-Holler)
- Optimize layout flattening, particularly reducing retain/release operations. [Adlai Holler](https://github.com/Adlai-Holler) - Optimize layout flattening, particularly reducing retain/release operations. [Adlai Holler](https://github.com/Adlai-Holler)
- Create a method to transfer strong C-arrays into immutable NSArrays, reducing retain/release traffic. [Adlai Holler](https://github.com/Adlai-Holler)
## 2.7 ## 2.7
- Fix pager node for interface coalescing. [Max Wang](https://github.com/wsdwsd0829) [#877](https://github.com/TextureGroup/Texture/pull/877) - Fix pager node for interface coalescing. [Max Wang](https://github.com/wsdwsd0829) [#877](https://github.com/TextureGroup/Texture/pull/877)

View File

@ -23,6 +23,7 @@
#import <AsyncDisplayKit/ASCollectionInternal.h> #import <AsyncDisplayKit/ASCollectionInternal.h>
#import <AsyncDisplayKit/ASCollectionLayout.h> #import <AsyncDisplayKit/ASCollectionLayout.h>
#import <AsyncDisplayKit/ASCollectionNode+Beta.h> #import <AsyncDisplayKit/ASCollectionNode+Beta.h>
#import <AsyncDisplayKit/ASCollections.h>
#import <AsyncDisplayKit/ASCollectionViewLayoutController.h> #import <AsyncDisplayKit/ASCollectionViewLayoutController.h>
#import <AsyncDisplayKit/ASCollectionViewLayoutFacilitatorProtocol.h> #import <AsyncDisplayKit/ASCollectionViewLayoutFacilitatorProtocol.h>
#import <AsyncDisplayKit/ASCollectionViewFlowLayoutInspector.h> #import <AsyncDisplayKit/ASCollectionViewFlowLayoutInspector.h>
@ -751,19 +752,7 @@ static NSString * const kReuseIdentifier = @"_ASCollectionReuseIdentifier";
- (NSArray<NSIndexPath *> *)convertIndexPathsToCollectionNode:(NSArray<NSIndexPath *> *)indexPaths - (NSArray<NSIndexPath *> *)convertIndexPathsToCollectionNode:(NSArray<NSIndexPath *> *)indexPaths
{ {
if (indexPaths == nil) { return ASArrayByFlatMapping(indexPaths, NSIndexPath *viewIndexPath, [self convertIndexPathToCollectionNode:viewIndexPath]);
return nil;
}
NSMutableArray<NSIndexPath *> *indexPathsArray = [NSMutableArray arrayWithCapacity:indexPaths.count];
for (NSIndexPath *indexPathInView in indexPaths) {
NSIndexPath *indexPath = [self convertIndexPathToCollectionNode:indexPathInView];
if (indexPath != nil) {
[indexPathsArray addObject:indexPath];
}
}
return indexPathsArray;
} }
- (ASCellNode *)supplementaryNodeForElementKind:(NSString *)elementKind atIndexPath:(NSIndexPath *)indexPath - (ASCellNode *)supplementaryNodeForElementKind:(NSString *)elementKind atIndexPath:(NSIndexPath *)indexPath
@ -2225,13 +2214,7 @@ static NSString * const kReuseIdentifier = @"_ASCollectionReuseIdentifier";
return; return;
} }
NSMutableArray<NSIndexPath *> *uikitIndexPaths = [NSMutableArray arrayWithCapacity:nodes.count]; auto uikitIndexPaths = ASArrayByFlatMapping(nodes, ASCellNode *node, [self indexPathForNode:node]);
for (ASCellNode *node in nodes) {
NSIndexPath *uikitIndexPath = [self indexPathForNode:node];
if (uikitIndexPath != nil) {
[uikitIndexPaths addObject:uikitIndexPath];
}
}
[_layoutFacilitator collectionViewWillEditCellsAtIndexPaths:uikitIndexPaths batched:NO]; [_layoutFacilitator collectionViewWillEditCellsAtIndexPaths:uikitIndexPaths batched:NO];

42
Source/ASCollections.h Normal file
View File

@ -0,0 +1,42 @@
//
// ASCollections.h
// Texture
//
// Copyright (c) 2018-present, Pinterest, Inc. All rights reserved.
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
#import <Foundation/Foundation.h>
NS_ASSUME_NONNULL_BEGIN
@interface NSArray<__covariant ObjectType> (ASCollections)
/**
* Create an immutable NSArray from a C-array of strong pointers.
*
* Note: The memory for the array you pass in will be zero'd (to prevent ARC from releasing
* the references when the array goes out of scope.)
*
* Can be combined with vector like:
* vector<NSString *> vec;
* vec.push_back(@"foo");
* vec.push_back(@"bar");
* NSArray *arr = [NSArray arrayTransferring:vec.data() count:vec.size()]
* ** vec is now { nil, nil } **
*
* Unfortunately making a convenience method to do this is currently impossible because
* vector<NSString *> can't be converted to vector<id> by the compiler (silly).
*
* See the private __CFArrayCreateTransfer function.
*/
+ (NSArray<ObjectType> *)arrayByTransferring:(ObjectType _Nonnull __strong * _Nonnull)pointers
count:(NSUInteger)count NS_RETURNS_RETAINED;
@end
NS_ASSUME_NONNULL_END

65
Source/ASCollections.m Normal file
View File

@ -0,0 +1,65 @@
//
// ASCollections.m
// Texture
//
// Copyright (c) 2018-present, Pinterest, Inc. All rights reserved.
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
#import "ASCollections.h"
/**
* A private allocator that signals to our retain callback to skip the retain.
* It behaves the same as the default allocator, but acts as a signal that we
* are creating a transfer array so we should skip the retain.
*/
static CFAllocatorRef gTransferAllocator;
static const void *ASTransferRetain(CFAllocatorRef allocator, const void *val) {
if (allocator == gTransferAllocator) {
// Transfer allocator. Ignore retain and pass through.
return val;
} else {
// Other allocator. Retain like normal.
// This happens when they make a mutable copy.
return (&kCFTypeArrayCallBacks)->retain(allocator, val);
}
}
@implementation NSArray (ASCollections)
+ (NSArray *)arrayByTransferring:(__strong id *)pointers count:(NSUInteger)count NS_RETURNS_RETAINED
{
// Custom callbacks that point to our ASTransferRetain callback.
static CFArrayCallBacks callbacks;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
callbacks = kCFTypeArrayCallBacks;
callbacks.retain = ASTransferRetain;
CFAllocatorContext ctx;
CFAllocatorGetContext(NULL, &ctx);
gTransferAllocator = CFAllocatorCreate(NULL, &ctx);
});
// NSZeroArray fast path.
if (count == 0) {
return @[]; // Does not actually call +array when optimized.
}
// NSSingleObjectArray fast path. Retain/release here is worth it.
if (count == 1) {
NSArray *result = [[NSArray alloc] initWithObjects:pointers count:1];
pointers[0] = nil;
return result;
}
NSArray *result = (__bridge_transfer NSArray *)CFArrayCreate(gTransferAllocator, (void *)pointers, count, &callbacks);
memset(pointers, 0, count * sizeof(id));
return result;
}
@end

View File

@ -12,6 +12,8 @@
#import <AsyncDisplayKit/ASExperimentalFeatures.h> #import <AsyncDisplayKit/ASExperimentalFeatures.h>
#import <AsyncDisplayKit/ASCollections.h>
NSArray<NSString *> *ASExperimentalFeaturesGetNames(ASExperimentalFeatures flags) NSArray<NSString *> *ASExperimentalFeaturesGetNames(ASExperimentalFeatures flags)
{ {
NSArray *allNames = ASCreateOnce((@[@"exp_graphics_contexts", NSArray *allNames = ASCreateOnce((@[@"exp_graphics_contexts",

View File

@ -24,6 +24,7 @@
#import <AsyncDisplayKit/ASBatchFetching.h> #import <AsyncDisplayKit/ASBatchFetching.h>
#import <AsyncDisplayKit/ASCellNode+Internal.h> #import <AsyncDisplayKit/ASCellNode+Internal.h>
#import <AsyncDisplayKit/ASCollectionElement.h> #import <AsyncDisplayKit/ASCollectionElement.h>
#import <AsyncDisplayKit/ASCollections.h>
#import <AsyncDisplayKit/ASConfigurationInternal.h> #import <AsyncDisplayKit/ASConfigurationInternal.h>
#import <AsyncDisplayKit/ASDelegateProxy.h> #import <AsyncDisplayKit/ASDelegateProxy.h>
#import <AsyncDisplayKit/ASDisplayNodeExtras.h> #import <AsyncDisplayKit/ASDisplayNodeExtras.h>

View File

@ -96,6 +96,7 @@
#import <AsyncDisplayKit/_ASAsyncTransaction.h> #import <AsyncDisplayKit/_ASAsyncTransaction.h>
#import <AsyncDisplayKit/_ASAsyncTransactionGroup.h> #import <AsyncDisplayKit/_ASAsyncTransactionGroup.h>
#import <AsyncDisplayKit/_ASAsyncTransactionContainer.h> #import <AsyncDisplayKit/_ASAsyncTransactionContainer.h>
#import <AsyncDisplayKit/ASCollections.h>
#import <AsyncDisplayKit/_ASDisplayLayer.h> #import <AsyncDisplayKit/_ASDisplayLayer.h>
#import <AsyncDisplayKit/_ASDisplayView.h> #import <AsyncDisplayKit/_ASDisplayView.h>
#import <AsyncDisplayKit/ASDisplayNode+Beta.h> #import <AsyncDisplayKit/ASDisplayNode+Beta.h>

View File

@ -214,13 +214,18 @@
/** /**
* Create a new array by mapping `collection` over `work`, ignoring nil. * Create a new array by mapping `collection` over `work`, ignoring nil.
*/ */
#define ASArrayByFlatMapping(collection, decl, work) ({ \ #define ASArrayByFlatMapping(collectionArg, decl, work) ({ \
NSMutableArray *a = [[NSMutableArray alloc] init]; \ id __collection = collectionArg; \
for (decl in collection) {\ NSArray *__result; \
id result = work; \ if (__collection) { \
if (result != nil) { \ id __buf[[__collection count]]; \
[a addObject:result]; \ NSUInteger __i = 0; \
for (decl in __collection) {\
if ((__buf[__i] = work)) { \
__i++; \
} \
} \ } \
__result = [NSArray arrayByTransferring:__buf count:__i]; \
} \ } \
a; \ __result; \
}) })

View File

@ -22,6 +22,7 @@
#import <AsyncDisplayKit/ASCollectionElement.h> #import <AsyncDisplayKit/ASCollectionElement.h>
#import <AsyncDisplayKit/ASCollectionLayoutContext.h> #import <AsyncDisplayKit/ASCollectionLayoutContext.h>
#import <AsyncDisplayKit/ASCollectionLayoutDefines.h> #import <AsyncDisplayKit/ASCollectionLayoutDefines.h>
#import <AsyncDisplayKit/ASCollections.h>
#import <AsyncDisplayKit/ASElementMap.h> #import <AsyncDisplayKit/ASElementMap.h>
#import <AsyncDisplayKit/ASLayout.h> #import <AsyncDisplayKit/ASLayout.h>
#import <AsyncDisplayKit/ASStackLayoutSpec.h> #import <AsyncDisplayKit/ASStackLayoutSpec.h>

View File

@ -17,6 +17,7 @@
#import <AsyncDisplayKit/ASAssert.h> #import <AsyncDisplayKit/ASAssert.h>
#import <AsyncDisplayKit/ASCellNode.h> #import <AsyncDisplayKit/ASCellNode.h>
#import <AsyncDisplayKit/ASCollectionElement.h> #import <AsyncDisplayKit/ASCollectionElement.h>
#import <AsyncDisplayKit/ASCollections.h>
#import <AsyncDisplayKit/ASCollectionLayoutContext.h> #import <AsyncDisplayKit/ASCollectionLayoutContext.h>
#import <AsyncDisplayKit/ASCollectionLayoutDefines.h> #import <AsyncDisplayKit/ASCollectionLayoutDefines.h>
#import <AsyncDisplayKit/ASCollectionLayoutState.h> #import <AsyncDisplayKit/ASCollectionLayoutState.h>
@ -102,9 +103,9 @@
return [[ASCollectionLayoutState alloc] initWithContext:context]; return [[ASCollectionLayoutState alloc] initWithContext:context];
} }
NSMutableArray<_ASGalleryLayoutItem *> *children = ASArrayByFlatMapping(elements.itemElements, NSArray<_ASGalleryLayoutItem *> *children = ASArrayByFlatMapping(elements.itemElements,
ASCollectionElement *element, ASCollectionElement *element,
[[_ASGalleryLayoutItem alloc] initWithItemSize:itemSize collectionElement:element]); [[_ASGalleryLayoutItem alloc] initWithItemSize:itemSize collectionElement:element]);
if (children.count == 0) { if (children.count == 0) {
return [[ASCollectionLayoutState alloc] initWithContext:context]; return [[ASCollectionLayoutState alloc] initWithContext:context];
} }

View File

@ -19,6 +19,7 @@
#import <queue> #import <queue>
#import <AsyncDisplayKit/ASCollections.h>
#import <AsyncDisplayKit/ASDimension.h> #import <AsyncDisplayKit/ASDimension.h>
#import <AsyncDisplayKit/ASLayoutSpecUtilities.h> #import <AsyncDisplayKit/ASLayoutSpecUtilities.h>
#import <AsyncDisplayKit/ASLayoutSpec+Subclasses.h> #import <AsyncDisplayKit/ASLayoutSpec+Subclasses.h>
@ -236,7 +237,7 @@ static std::atomic_bool static_retainsSublayoutLayoutElements = ATOMIC_VAR_INIT(
queue.push_back({sublayout, sublayout.position}); queue.push_back({sublayout, sublayout.position});
} }
auto flattenedSublayouts = [[NSMutableArray<ASLayout *> alloc] init]; std::vector<ASLayout *> flattenedSublayouts;
while (!queue.empty()) { while (!queue.empty()) {
const Context context = std::move(queue.front()); const Context context = std::move(queue.front());
@ -254,9 +255,9 @@ static std::atomic_bool static_retainsSublayoutLayoutElements = ATOMIC_VAR_INIT(
size:layout.size size:layout.size
position:absolutePosition position:absolutePosition
sublayouts:@[]]; sublayouts:@[]];
[flattenedSublayouts addObject:newLayout]; flattenedSublayouts.push_back(newLayout);
} else { } else {
[flattenedSublayouts addObject:layout]; flattenedSublayouts.push_back(layout);
} }
} else if (sublayoutsCount > 0) { } else if (sublayoutsCount > 0) {
// Fast-reverse-enumerate the sublayouts array by copying it into a C-array and push_front'ing each into the queue. // Fast-reverse-enumerate the sublayouts array by copying it into a C-array and push_front'ing each into the queue.
@ -268,7 +269,10 @@ static std::atomic_bool static_retainsSublayoutLayoutElements = ATOMIC_VAR_INIT(
} }
} }
ASLayout *layout = [ASLayout layoutWithLayoutElement:_layoutElement size:_size sublayouts:flattenedSublayouts]; NSArray *array = [NSArray arrayByTransferring:flattenedSublayouts.data() count:flattenedSublayouts.size()];
// flattenedSublayouts is now all nils.
ASLayout *layout = [ASLayout layoutWithLayoutElement:_layoutElement size:_size sublayouts:array];
// All flattened layouts must have this flag enabled // All flattened layouts must have this flag enabled
// to ensure sublayout elements are retained until the layouts are applied. // to ensure sublayout elements are retained until the layouts are applied.
layout.retainSublayoutLayoutElements = YES; layout.retainSublayoutLayoutElements = YES;

View File

@ -20,6 +20,7 @@
#import <AsyncDisplayKit/ASLayoutSpec+Subclasses.h> #import <AsyncDisplayKit/ASLayoutSpec+Subclasses.h>
#import <AsyncDisplayKit/ASCollections.h>
#import <AsyncDisplayKit/ASLayoutElementStylePrivate.h> #import <AsyncDisplayKit/ASLayoutElementStylePrivate.h>
#import <AsyncDisplayKit/ASTraitCollection.h> #import <AsyncDisplayKit/ASTraitCollection.h>
#import <AsyncDisplayKit/ASEqualityHelpers.h> #import <AsyncDisplayKit/ASEqualityHelpers.h>

View File

@ -17,6 +17,7 @@
#import <AsyncDisplayKit/_ASHierarchyChangeSet.h> #import <AsyncDisplayKit/_ASHierarchyChangeSet.h>
#import <AsyncDisplayKit/ASInternalHelpers.h> #import <AsyncDisplayKit/ASInternalHelpers.h>
#import <AsyncDisplayKit/ASCollections.h>
#import <AsyncDisplayKit/NSIndexSet+ASHelpers.h> #import <AsyncDisplayKit/NSIndexSet+ASHelpers.h>
#import <AsyncDisplayKit/ASAssert.h> #import <AsyncDisplayKit/ASAssert.h>
#import <AsyncDisplayKit/ASDisplayNode+Beta.h> #import <AsyncDisplayKit/ASDisplayNode+Beta.h>

View File

@ -0,0 +1,59 @@
//
// ASCollectionsTests.m
// Texture
//
// Copyright (c) 2018-present, Pinterest, Inc. All rights reserved.
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
#import <XCTest/XCTest.h>
#import <AsyncDisplayKit/ASCollections.h>
@interface ASCollectionsTests : XCTestCase
@end
@implementation ASCollectionsTests
- (void)testTransferArray {
id objs[2];
objs[0] = [NSObject new];
id o0 = objs[0];
objs[1] = [NSObject new];
__weak id w0 = objs[0];
__weak id w1 = objs[1];
CFTypeRef cf0 = (__bridge CFTypeRef)objs[0];
CFTypeRef cf1 = (__bridge CFTypeRef)objs[1];
XCTAssertEqual(CFGetRetainCount(cf0), 2);
XCTAssertEqual(CFGetRetainCount(cf1), 1);
NSArray *arr = [NSArray arrayByTransferring:objs count:2];
XCTAssertNil(objs[0]);
XCTAssertNil(objs[1]);
XCTAssertEqual(CFGetRetainCount(cf0), 2);
XCTAssertEqual(CFGetRetainCount(cf1), 1);
NSArray *immutableCopy = [arr copy];
XCTAssertEqual(immutableCopy, arr);
XCTAssertEqual(CFGetRetainCount(cf0), 2);
XCTAssertEqual(CFGetRetainCount(cf1), 1);
NSMutableArray *mc = [arr mutableCopy];
XCTAssertEqual(CFGetRetainCount(cf0), 3);
XCTAssertEqual(CFGetRetainCount(cf1), 2);
arr = nil;
immutableCopy = nil;
XCTAssertEqual(CFGetRetainCount(cf0), 2);
XCTAssertEqual(CFGetRetainCount(cf1), 1);
[mc removeObjectAtIndex:0];
XCTAssertEqual(CFGetRetainCount(cf0), 1);
XCTAssertEqual(CFGetRetainCount(cf1), 1);
[mc removeObjectAtIndex:0];
XCTAssertEqual(CFGetRetainCount(cf0), 1);
XCTAssertNil(w1);
o0 = nil;
XCTAssertNil(w0);
}
@end