IGListKit Support II: Electric Boogaloo (#2942)

* Reimplement IGListKit support in a cleaner way

* Rename and fix some stuff

* Fix supplementaries more

* Update docs

* Update test

* Cleanup minor things

* Tweak it

* Indentation

* Remove irrelevant changes

* Break out cell into its own file

* Fix indentation

* Address feedback
This commit is contained in:
Adlai Holler
2017-01-30 11:16:59 -08:00
committed by GitHub
parent 34338cadeb
commit 38aac9d019
70 changed files with 2446 additions and 182 deletions

View File

@@ -17,6 +17,7 @@ before_install:
install: echo "<3" install: echo "<3"
env: env:
- MODE=tests - MODE=tests
- MODE=tests_listkit
- MODE=examples-pt1 - MODE=examples-pt1
- MODE=examples-pt2 - MODE=examples-pt2
- MODE=examples-pt3 - MODE=examples-pt3

View File

@@ -0,0 +1,394 @@
// !$*UTF8*$!
{
archiveVersion = 1;
classes = {
};
objectVersion = 46;
objects = {
/* Begin PBXBuildFile section */
BD860CAB842324FDF0B3105C /* libPods-ASDKListKitTests.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 1FEACA22D54B3609C19BB4CE /* libPods-ASDKListKitTests.a */; };
CC5532391E16F2A90011C01F /* ASListTestSupplementarySource.m in Sources */ = {isa = PBXBuildFile; fileRef = CC55322D1E16F2A90011C01F /* ASListTestSupplementarySource.m */; };
CC55323A1E16F2A90011C01F /* ASListTestSupplementaryNode.m in Sources */ = {isa = PBXBuildFile; fileRef = CC55322F1E16F2A90011C01F /* ASListTestSupplementaryNode.m */; };
CC55323B1E16F2A90011C01F /* ASListKitTestAdapterDataSource.m in Sources */ = {isa = PBXBuildFile; fileRef = CC5532311E16F2A90011C01F /* ASListKitTestAdapterDataSource.m */; };
CC55323C1E16F2A90011C01F /* ASListTestSection.m in Sources */ = {isa = PBXBuildFile; fileRef = CC5532331E16F2A90011C01F /* ASListTestSection.m */; };
CC55323D1E16F2A90011C01F /* ASListTestCellNode.m in Sources */ = {isa = PBXBuildFile; fileRef = CC5532351E16F2A90011C01F /* ASListTestCellNode.m */; };
CC55323E1E16F2A90011C01F /* ASListTestObject.m in Sources */ = {isa = PBXBuildFile; fileRef = CC5532371E16F2A90011C01F /* ASListTestObject.m */; };
CC55323F1E16F2A90011C01F /* ASListKitTests.m in Sources */ = {isa = PBXBuildFile; fileRef = CC5532381E16F2A90011C01F /* ASListKitTests.m */; };
/* End PBXBuildFile section */
/* Begin PBXFileReference section */
1FEACA22D54B3609C19BB4CE /* libPods-ASDKListKitTests.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-ASDKListKitTests.a"; sourceTree = BUILT_PRODUCTS_DIR; };
B1FDA57F88BB590E403D7BB8 /* Pods-ASDKListKitTests.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-ASDKListKitTests.debug.xcconfig"; path = "Pods/Target Support Files/Pods-ASDKListKitTests/Pods-ASDKListKitTests.debug.xcconfig"; sourceTree = "<group>"; };
CC5532231E16EB9D0011C01F /* ASDKListKitTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = ASDKListKitTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
CC5532281E16EB9D0011C01F /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
CC55322C1E16F2A90011C01F /* ASListTestSupplementarySource.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ASListTestSupplementarySource.h; sourceTree = "<group>"; };
CC55322D1E16F2A90011C01F /* ASListTestSupplementarySource.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ASListTestSupplementarySource.m; sourceTree = "<group>"; };
CC55322E1E16F2A90011C01F /* ASListTestSupplementaryNode.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ASListTestSupplementaryNode.h; sourceTree = "<group>"; };
CC55322F1E16F2A90011C01F /* ASListTestSupplementaryNode.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ASListTestSupplementaryNode.m; sourceTree = "<group>"; };
CC5532301E16F2A90011C01F /* ASListKitTestAdapterDataSource.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ASListKitTestAdapterDataSource.h; sourceTree = "<group>"; };
CC5532311E16F2A90011C01F /* ASListKitTestAdapterDataSource.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ASListKitTestAdapterDataSource.m; sourceTree = "<group>"; };
CC5532321E16F2A90011C01F /* ASListTestSection.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ASListTestSection.h; sourceTree = "<group>"; };
CC5532331E16F2A90011C01F /* ASListTestSection.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ASListTestSection.m; sourceTree = "<group>"; };
CC5532341E16F2A90011C01F /* ASListTestCellNode.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ASListTestCellNode.h; sourceTree = "<group>"; };
CC5532351E16F2A90011C01F /* ASListTestCellNode.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ASListTestCellNode.m; sourceTree = "<group>"; };
CC5532361E16F2A90011C01F /* ASListTestObject.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ASListTestObject.h; sourceTree = "<group>"; };
CC5532371E16F2A90011C01F /* ASListTestObject.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ASListTestObject.m; sourceTree = "<group>"; };
CC5532381E16F2A90011C01F /* ASListKitTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ASListKitTests.m; sourceTree = "<group>"; };
CC55326C1E16F67A0011C01F /* ASXCTExtensions.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ASXCTExtensions.h; sourceTree = "<group>"; };
D6BDED6F23A72F40F571EEF0 /* Pods-ASDKListKitTests.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-ASDKListKitTests.release.xcconfig"; path = "Pods/Target Support Files/Pods-ASDKListKitTests/Pods-ASDKListKitTests.release.xcconfig"; sourceTree = "<group>"; };
/* End PBXFileReference section */
/* Begin PBXFrameworksBuildPhase section */
CC5532201E16EB9D0011C01F /* Frameworks */ = {
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
BD860CAB842324FDF0B3105C /* libPods-ASDKListKitTests.a in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXFrameworksBuildPhase section */
/* Begin PBXGroup section */
72C6817154F7AC11E373624A /* Pods */ = {
isa = PBXGroup;
children = (
B1FDA57F88BB590E403D7BB8 /* Pods-ASDKListKitTests.debug.xcconfig */,
D6BDED6F23A72F40F571EEF0 /* Pods-ASDKListKitTests.release.xcconfig */,
);
name = Pods;
sourceTree = "<group>";
};
74DAA5F5D522433F103348B7 /* Frameworks */ = {
isa = PBXGroup;
children = (
1FEACA22D54B3609C19BB4CE /* libPods-ASDKListKitTests.a */,
);
name = Frameworks;
sourceTree = "<group>";
};
CC5532181E16EB7A0011C01F = {
isa = PBXGroup;
children = (
CC5532251E16EB9D0011C01F /* ASDKListKitTests */,
CC5532241E16EB9D0011C01F /* Products */,
72C6817154F7AC11E373624A /* Pods */,
74DAA5F5D522433F103348B7 /* Frameworks */,
);
indentWidth = 2;
sourceTree = "<group>";
tabWidth = 2;
usesTabs = 0;
};
CC5532241E16EB9D0011C01F /* Products */ = {
isa = PBXGroup;
children = (
CC5532231E16EB9D0011C01F /* ASDKListKitTests.xctest */,
);
name = Products;
sourceTree = "<group>";
};
CC5532251E16EB9D0011C01F /* ASDKListKitTests */ = {
isa = PBXGroup;
children = (
CC55326D1E16F67D0011C01F /* Common */,
CC55326E1E170A740011C01F /* ListKit Fixtures */,
CC5532381E16F2A90011C01F /* ASListKitTests.m */,
CC5532281E16EB9D0011C01F /* Info.plist */,
);
path = ASDKListKitTests;
sourceTree = "<group>";
};
CC55326D1E16F67D0011C01F /* Common */ = {
isa = PBXGroup;
children = (
CC55326C1E16F67A0011C01F /* ASXCTExtensions.h */,
);
name = Common;
sourceTree = "<group>";
};
CC55326E1E170A740011C01F /* ListKit Fixtures */ = {
isa = PBXGroup;
children = (
CC55322C1E16F2A90011C01F /* ASListTestSupplementarySource.h */,
CC55322D1E16F2A90011C01F /* ASListTestSupplementarySource.m */,
CC55322E1E16F2A90011C01F /* ASListTestSupplementaryNode.h */,
CC55322F1E16F2A90011C01F /* ASListTestSupplementaryNode.m */,
CC5532301E16F2A90011C01F /* ASListKitTestAdapterDataSource.h */,
CC5532311E16F2A90011C01F /* ASListKitTestAdapterDataSource.m */,
CC5532321E16F2A90011C01F /* ASListTestSection.h */,
CC5532331E16F2A90011C01F /* ASListTestSection.m */,
CC5532341E16F2A90011C01F /* ASListTestCellNode.h */,
CC5532351E16F2A90011C01F /* ASListTestCellNode.m */,
CC5532361E16F2A90011C01F /* ASListTestObject.h */,
CC5532371E16F2A90011C01F /* ASListTestObject.m */,
);
name = "ListKit Fixtures";
sourceTree = "<group>";
};
/* End PBXGroup section */
/* Begin PBXNativeTarget section */
CC5532221E16EB9D0011C01F /* ASDKListKitTests */ = {
isa = PBXNativeTarget;
buildConfigurationList = CC5532291E16EB9D0011C01F /* Build configuration list for PBXNativeTarget "ASDKListKitTests" */;
buildPhases = (
614B24BFF3DA58512D2E2147 /* [CP] Check Pods Manifest.lock */,
CC55321F1E16EB9D0011C01F /* Sources */,
CC5532201E16EB9D0011C01F /* Frameworks */,
CC5532211E16EB9D0011C01F /* Resources */,
989E6C194A1983B8B21AB82F /* [CP] Embed Pods Frameworks */,
876CE14CAF6A87E34577E157 /* [CP] Copy Pods Resources */,
);
buildRules = (
);
dependencies = (
);
name = ASDKListKitTests;
productName = ASDKListKitTests;
productReference = CC5532231E16EB9D0011C01F /* ASDKListKitTests.xctest */;
productType = "com.apple.product-type.bundle.unit-test";
};
/* End PBXNativeTarget section */
/* Begin PBXProject section */
CC5532191E16EB7A0011C01F /* Project object */ = {
isa = PBXProject;
attributes = {
LastUpgradeCheck = 0820;
TargetAttributes = {
CC5532221E16EB9D0011C01F = {
CreatedOnToolsVersion = 8.2.1;
ProvisioningStyle = Automatic;
};
};
};
buildConfigurationList = CC55321C1E16EB7A0011C01F /* Build configuration list for PBXProject "ASDKListKit" */;
compatibilityVersion = "Xcode 3.2";
developmentRegion = English;
hasScannedForEncodings = 0;
knownRegions = (
en,
);
mainGroup = CC5532181E16EB7A0011C01F;
productRefGroup = CC5532241E16EB9D0011C01F /* Products */;
projectDirPath = "";
projectRoot = "";
targets = (
CC5532221E16EB9D0011C01F /* ASDKListKitTests */,
);
};
/* End PBXProject section */
/* Begin PBXResourcesBuildPhase section */
CC5532211E16EB9D0011C01F /* Resources */ = {
isa = PBXResourcesBuildPhase;
buildActionMask = 2147483647;
files = (
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXResourcesBuildPhase section */
/* Begin PBXShellScriptBuildPhase section */
614B24BFF3DA58512D2E2147 /* [CP] Check Pods Manifest.lock */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
);
inputPaths = (
);
name = "[CP] Check Pods Manifest.lock";
outputPaths = (
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "diff \"${PODS_ROOT}/../Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [[ $? != 0 ]] ; then\n cat << EOM\nerror: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\nEOM\n exit 1\nfi\n";
showEnvVarsInLog = 0;
};
876CE14CAF6A87E34577E157 /* [CP] Copy Pods Resources */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
);
inputPaths = (
);
name = "[CP] Copy Pods Resources";
outputPaths = (
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-ASDKListKitTests/Pods-ASDKListKitTests-resources.sh\"\n";
showEnvVarsInLog = 0;
};
989E6C194A1983B8B21AB82F /* [CP] Embed Pods Frameworks */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
);
inputPaths = (
);
name = "[CP] Embed Pods Frameworks";
outputPaths = (
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-ASDKListKitTests/Pods-ASDKListKitTests-frameworks.sh\"\n";
showEnvVarsInLog = 0;
};
/* End PBXShellScriptBuildPhase section */
/* Begin PBXSourcesBuildPhase section */
CC55321F1E16EB9D0011C01F /* Sources */ = {
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
CC55323E1E16F2A90011C01F /* ASListTestObject.m in Sources */,
CC5532391E16F2A90011C01F /* ASListTestSupplementarySource.m in Sources */,
CC55323D1E16F2A90011C01F /* ASListTestCellNode.m in Sources */,
CC55323B1E16F2A90011C01F /* ASListKitTestAdapterDataSource.m in Sources */,
CC55323C1E16F2A90011C01F /* ASListTestSection.m in Sources */,
CC55323F1E16F2A90011C01F /* ASListKitTests.m in Sources */,
CC55323A1E16F2A90011C01F /* ASListTestSupplementaryNode.m in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXSourcesBuildPhase section */
/* Begin XCBuildConfiguration section */
CC55321D1E16EB7A0011C01F /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
};
name = Debug;
};
CC55321E1E16EB7A0011C01F /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
};
name = Release;
};
CC55322A1E16EB9D0011C01F /* Debug */ = {
isa = XCBuildConfiguration;
baseConfigurationReference = B1FDA57F88BB590E403D7BB8 /* Pods-ASDKListKitTests.debug.xcconfig */;
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
CLANG_ANALYZER_NONNULL = YES;
CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
CLANG_CXX_LIBRARY = "libc++";
CLANG_ENABLE_MODULES = YES;
CLANG_ENABLE_OBJC_ARC = YES;
CLANG_WARN_BOOL_CONVERSION = YES;
CLANG_WARN_CONSTANT_CONVERSION = YES;
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
CLANG_WARN_EMPTY_BODY = YES;
CLANG_WARN_ENUM_CONVERSION = YES;
CLANG_WARN_INFINITE_RECURSION = YES;
CLANG_WARN_INT_CONVERSION = YES;
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
CLANG_WARN_SUSPICIOUS_MOVE = YES;
CLANG_WARN_UNREACHABLE_CODE = YES;
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
COPY_PHASE_STRIP = NO;
DEBUG_INFORMATION_FORMAT = dwarf;
ENABLE_STRICT_OBJC_MSGSEND = YES;
ENABLE_TESTABILITY = YES;
GCC_C_LANGUAGE_STANDARD = gnu99;
GCC_DYNAMIC_NO_PIC = NO;
GCC_NO_COMMON_BLOCKS = YES;
GCC_OPTIMIZATION_LEVEL = 0;
GCC_PREPROCESSOR_DEFINITIONS = (
"DEBUG=1",
"$(inherited)",
);
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
GCC_WARN_UNDECLARED_SELECTOR = YES;
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
INFOPLIST_FILE = ASDKListKitTests/Info.plist;
IPHONEOS_DEPLOYMENT_TARGET = 10.2;
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
MTL_ENABLE_DEBUG_INFO = YES;
ONLY_ACTIVE_ARCH = YES;
PRODUCT_BUNDLE_IDENTIFIER = asyncdisplaykit.ASDKListKitTests;
PRODUCT_NAME = "$(TARGET_NAME)";
SDKROOT = iphoneos;
};
name = Debug;
};
CC55322B1E16EB9D0011C01F /* Release */ = {
isa = XCBuildConfiguration;
baseConfigurationReference = D6BDED6F23A72F40F571EEF0 /* Pods-ASDKListKitTests.release.xcconfig */;
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
CLANG_ANALYZER_NONNULL = YES;
CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
CLANG_CXX_LIBRARY = "libc++";
CLANG_ENABLE_MODULES = YES;
CLANG_ENABLE_OBJC_ARC = YES;
CLANG_WARN_BOOL_CONVERSION = YES;
CLANG_WARN_CONSTANT_CONVERSION = YES;
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
CLANG_WARN_EMPTY_BODY = YES;
CLANG_WARN_ENUM_CONVERSION = YES;
CLANG_WARN_INFINITE_RECURSION = YES;
CLANG_WARN_INT_CONVERSION = YES;
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
CLANG_WARN_SUSPICIOUS_MOVE = YES;
CLANG_WARN_UNREACHABLE_CODE = YES;
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
COPY_PHASE_STRIP = NO;
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
ENABLE_NS_ASSERTIONS = NO;
ENABLE_STRICT_OBJC_MSGSEND = YES;
GCC_C_LANGUAGE_STANDARD = gnu99;
GCC_NO_COMMON_BLOCKS = YES;
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
GCC_WARN_UNDECLARED_SELECTOR = YES;
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
INFOPLIST_FILE = ASDKListKitTests/Info.plist;
IPHONEOS_DEPLOYMENT_TARGET = 10.2;
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
MTL_ENABLE_DEBUG_INFO = NO;
PRODUCT_BUNDLE_IDENTIFIER = asyncdisplaykit.ASDKListKitTests;
PRODUCT_NAME = "$(TARGET_NAME)";
SDKROOT = iphoneos;
VALIDATE_PRODUCT = YES;
};
name = Release;
};
/* End XCBuildConfiguration section */
/* Begin XCConfigurationList section */
CC55321C1E16EB7A0011C01F /* Build configuration list for PBXProject "ASDKListKit" */ = {
isa = XCConfigurationList;
buildConfigurations = (
CC55321D1E16EB7A0011C01F /* Debug */,
CC55321E1E16EB7A0011C01F /* Release */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
CC5532291E16EB9D0011C01F /* Build configuration list for PBXNativeTarget "ASDKListKitTests" */ = {
isa = XCConfigurationList;
buildConfigurations = (
CC55322A1E16EB9D0011C01F /* Debug */,
CC55322B1E16EB9D0011C01F /* Release */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
/* End XCConfigurationList section */
};
rootObject = CC5532191E16EB7A0011C01F /* Project object */;
}

View File

@@ -0,0 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<Workspace
version = "1.0">
<FileRef
location = "self:ASDKListKit.xcodeproj">
</FileRef>
</Workspace>

View File

@@ -0,0 +1,10 @@
<?xml version="1.0" encoding="UTF-8"?>
<Workspace
version = "1.0">
<FileRef
location = "group:ASDKListKit.xcodeproj">
</FileRef>
<FileRef
location = "group:Pods/Pods.xcodeproj">
</FileRef>
</Workspace>

View File

@@ -0,0 +1,16 @@
//
// ASListKitTestAdapterDataSource.h
// AsyncDisplayKit
//
// Created by Adlai Holler on 12/25/16.
// Copyright © 2016 Facebook. All rights reserved.
//
#import <IGListKit/IGListKit.h>
@interface ASListKitTestAdapterDataSource : NSObject <IGListAdapterDataSource>
// array of numbers which is then passed to -[IGListTestSection setItems:]
@property (nonatomic, strong) NSArray <NSNumber *> *objects;
@end

View File

@@ -0,0 +1,30 @@
//
// ASListKitTestAdapterDataSource.m
// AsyncDisplayKit
//
// Created by Adlai Holler on 12/25/16.
// Copyright © 2016 Facebook. All rights reserved.
//
#import "ASListKitTestAdapterDataSource.h"
#import "ASListTestSection.h"
@implementation ASListKitTestAdapterDataSource
- (NSArray *)objectsForListAdapter:(IGListAdapter *)listAdapter
{
return self.objects;
}
- (IGListSectionController <IGListSectionType> *)listAdapter:(IGListAdapter *)listAdapter sectionControllerForObject:(id)object
{
ASListTestSection *section = [[ASListTestSection alloc] init];
return section;
}
- (nullable UIView *)emptyViewForListAdapter:(IGListAdapter *)listAdapter
{
return nil;
}
@end

View File

@@ -0,0 +1,110 @@
//
// ASListKitTests.m
// AsyncDisplayKit
//
// Created by Adlai Holler on 12/25/16.
// Copyright © 2016 Facebook. All rights reserved.
//
#import <XCTest/XCTest.h>
#import <AsyncDisplayKit/AsyncDisplayKit.h>
#import "ASListKitTestAdapterDataSource.h"
#import "ASXCTExtensions.h"
#import <JGMethodSwizzler/JGMethodSwizzler.h>
@interface ASListKitTests : XCTestCase
@property (nonatomic, strong) ASCollectionNode *collectionNode;
@property (nonatomic, strong) UICollectionView *collectionView;
@property (nonatomic, strong) IGListAdapter *adapter;
@property (nonatomic, strong) ASListKitTestAdapterDataSource *dataSource;
@property (nonatomic, strong) UICollectionViewFlowLayout *layout;
@property (nonatomic, strong) UIWindow *window;
@property (nonatomic) NSInteger reloadDataCount;
@end
@implementation ASListKitTests
- (void)setUp
{
[super setUp];
[ASCollectionView swizzleInstanceMethod:@selector(reloadData) withReplacement:JGMethodReplacementProviderBlock {
return JGMethodReplacement(void, ASCollectionView *) {
JGOriginalImplementation(void);
_reloadDataCount++;
};
}];
self.window = [[UIWindow alloc] initWithFrame:CGRectMake(0, 0, 100, 100)];
self.layout = [[UICollectionViewFlowLayout alloc] init];
self.collectionNode = [[ASCollectionNode alloc] initWithCollectionViewLayout:self.layout];
self.collectionNode.frame = self.window.bounds;
self.collectionView = self.collectionNode.view;
[self.window addSubnode:self.collectionNode];
IGListAdapterUpdater *updater = [[IGListAdapterUpdater alloc] init];
self.dataSource = [[ASListKitTestAdapterDataSource alloc] init];
self.adapter = [[IGListAdapter alloc] initWithUpdater:updater
viewController:nil
workingRangeSize:0];
self.adapter.dataSource = self.dataSource;
[self.adapter setASDKCollectionNode:self.collectionNode];
XCTAssertNotNil(self.adapter.collectionView, @"Adapter was not bound to collection view. You may have a stale copy of AsyncDisplayKit that was built without IG_LIST_KIT. Clean Builder Folder IMO.");
}
- (void)tearDown
{
[super tearDown];
XCTAssert([ASCollectionView deswizzleAllMethods]);
self.reloadDataCount = 0;
self.window = nil;
self.collectionNode = nil;
self.collectionView = nil;
self.adapter = nil;
self.dataSource = nil;
self.layout = nil;
}
- (void)test_whenAdapterUpdated_withObjectsOverflow_thatVisibleObjectsIsSubsetOfAllObjects
{
// each section controller returns n items sized 100x10
self.dataSource.objects = @[@1, @2, @3, @4, @5, @6];
XCTestExpectation *e = [self expectationWithDescription:@"Data update completed"];
[self.adapter performUpdatesAnimated:NO completion:^(BOOL finished) {
[e fulfill];
}];
[self waitForExpectationsWithTimeout:1 handler:nil];
self.collectionNode.view.contentOffset = CGPointMake(0, 30);
[self.collectionNode.view layoutIfNeeded];
NSArray *visibleObjects = [[self.adapter visibleObjects] sortedArrayUsingSelector:@selector(compare:)];
NSArray *expectedObjects = @[@3, @4, @5];
XCTAssertEqualObjects(visibleObjects, expectedObjects);
}
- (void)test_whenCollectionViewIsNotInAWindow_updaterDoesNotJustCallReloadData
{
[self.collectionView removeFromSuperview];
[self.collectionView layoutIfNeeded];
self.dataSource.objects = @[@1, @2, @3, @4, @5, @6];
XCTestExpectation *e = [self expectationWithDescription:@"Data update completed"];
[self.adapter performUpdatesAnimated:NO completion:^(BOOL finished) {
[e fulfill];
}];
[self waitForExpectationsWithTimeout:1 handler:nil];
[self.collectionView layoutIfNeeded];
XCTAssertEqual(self.reloadDataCount, 2);
}
@end

View File

@@ -0,0 +1,13 @@
//
// ASListTestCellNode.h
// AsyncDisplayKit
//
// Created by Adlai Holler on 12/25/16.
// Copyright © 2016 Facebook. All rights reserved.
//
#import <AsyncDisplayKit/AsyncDisplayKit.h>
@interface ASListTestCellNode : ASCellNode
@end

View File

@@ -0,0 +1,13 @@
//
// ASListTestCellNode.m
// AsyncDisplayKit
//
// Created by Adlai Holler on 12/25/16.
// Copyright © 2016 Facebook. All rights reserved.
//
#import "ASListTestCellNode.h"
@implementation ASListTestCellNode
@end

View File

@@ -0,0 +1,22 @@
//
// ASListTestObject.h
// AsyncDisplayKit
//
// Created by Adlai Holler on 12/25/16.
// Copyright © 2016 Facebook. All rights reserved.
//
#import <IGListKit/IGListKit.h>
NS_ASSUME_NONNULL_BEGIN
@interface ASListTestObject : NSObject <IGListDiffable, NSCopying>
- (instancetype)initWithKey:(id <NSCopying>)key value:(id)value;
@property (nonatomic, strong, readonly) id key;
@property (nonatomic, strong) id value;
@end
NS_ASSUME_NONNULL_END

View File

@@ -0,0 +1,49 @@
//
// ASListTestObject.m
// AsyncDisplayKit
//
// Created by Adlai Holler on 12/25/16.
// Copyright © 2016 Facebook. All rights reserved.
//
#import "ASListTestObject.h"
@implementation ASListTestObject
- (instancetype)initWithKey:(id)key value:(id)value
{
if (self = [super init]) {
_key = [key copy];
_value = value;
}
return self;
}
- (instancetype)copyWithZone:(NSZone *)zone
{
return [[ASListTestObject alloc] initWithKey:self.key value:self.value];
}
#pragma mark - IGListDiffable
- (id<NSObject>)diffIdentifier
{
return self.key;
}
- (BOOL)isEqualToDiffableObject:(id)object
{
if (object == self) {
return YES;
}
if ([object isKindOfClass:[ASListTestObject class]]) {
id k1 = self.key;
id k2 = [object key];
id v1 = self.value;
id v2 = [(ASListTestObject *)object value];
return (v1 == v2 || [v1 isEqual:v2]) && (k1 == k2 || [k1 isEqual:k2]);
}
return NO;
}
@end

View File

@@ -0,0 +1,18 @@
//
// ASListTestSection.h
// AsyncDisplayKit
//
// Created by Adlai Holler on 12/25/16.
// Copyright © 2016 Facebook. All rights reserved.
//
#import <IGListKit/IGListKit.h>
#import <AsyncDisplayKit/AsyncDisplayKit.h>
@interface ASListTestSection : IGListSectionController <IGListSectionType, ASSectionController>
@property (nonatomic) NSInteger itemCount;
@property (nonatomic) NSInteger selectedItemIndex;
@end

View File

@@ -0,0 +1,58 @@
//
// ASListTestSection.m
// AsyncDisplayKit
//
// Created by Adlai Holler on 12/25/16.
// Copyright © 2016 Facebook. All rights reserved.
//
#import "ASListTestSection.h"
#import "ASListTestCellNode.h"
@implementation ASListTestSection
- (instancetype)init
{
if (self = [super init])
{
_selectedItemIndex = NSNotFound;
}
return self;
}
- (NSInteger)numberOfItems
{
return self.itemCount;
}
- (CGSize)sizeForItemAtIndex:(NSInteger)index
{
ASDisplayNodeFailAssert(@"Did not expect %@ to be called.", NSStringFromSelector(_cmd));
return CGSizeMake(100, 10);
}
ASIGSectionControllerCellForIndexImplementation
- (void)didUpdateToObject:(id)object
{
if ([object isKindOfClass:[NSNumber class]])
{
self.itemCount = [object integerValue];
}
}
- (void)didSelectItemAtIndex:(NSInteger)index
{
self.selectedItemIndex = index;
}
- (ASCellNodeBlock)nodeBlockForItemAtIndex:(NSInteger)index
{
return ^{
ASListTestCellNode *node = [[ASListTestCellNode alloc] init];
node.style.preferredSize = CGSizeMake(100, 10);
return node;
};
}
@end

View File

@@ -0,0 +1,13 @@
//
// ASListTestSupplementaryNode.h
// AsyncDisplayKit
//
// Created by Adlai Holler on 12/25/16.
// Copyright © 2016 Facebook. All rights reserved.
//
#import <AsyncDisplayKit/AsyncDisplayKit.h>
@interface ASListTestSupplementaryNode : ASCellNode
@end

View File

@@ -0,0 +1,13 @@
//
// ASListTestSupplementaryNode.m
// AsyncDisplayKit
//
// Created by Adlai Holler on 12/25/16.
// Copyright © 2016 Facebook. All rights reserved.
//
#import "ASListTestSupplementaryNode.h"
@implementation ASListTestSupplementaryNode
@end

View File

@@ -0,0 +1,20 @@
//
// ASListTestSupplementarySource.h
// AsyncDisplayKit
//
// Created by Adlai Holler on 12/25/16.
// Copyright © 2016 Facebook. All rights reserved.
//
#import <IGListKit/IGListKit.h>
#import <AsyncDisplayKit/AsyncDisplayKit.h>
@interface ASListTestSupplementarySource : NSObject <IGListSupplementaryViewSource, ASSupplementaryNodeSource>
@property (nonatomic, strong, readwrite) NSArray<NSString *> *supportedElementKinds;
@property (nonatomic, weak) id<IGListCollectionContext> collectionContext;
@property (nonatomic, weak) IGListSectionController<IGListSectionType> *sectionController;
@end

View File

@@ -0,0 +1,24 @@
//
// ASListTestSupplementarySource.m
// AsyncDisplayKit
//
// Created by Adlai Holler on 12/25/16.
// Copyright © 2016 Facebook. All rights reserved.
//
#import "ASListTestSupplementarySource.h"
#import "ASListTestSupplementaryNode.h"
@implementation ASListTestSupplementarySource
ASIGSupplementarySourceViewForSupplementaryElementImplementation(self.sectionController)
ASIGSupplementarySourceSizeForSupplementaryElementImplementation
- (ASCellNode *)nodeForSupplementaryElementOfKind:(NSString *)elementKind atIndex:(NSInteger)index
{
ASListTestSupplementaryNode *node = [[ASListTestSupplementaryNode alloc] init];
node.style.preferredSize = CGSizeMake(100, 10);
return node;
}
@end

View File

@@ -0,0 +1,36 @@
/**
* XCTest extensions for CGGeometry.
*
* Prefer these to XCTAssert(CGRectEqualToRect(...)) because you get output
* that tells you what went wrong.
* Could use NSValue, but using strings makes the description messages shorter.
*/
#import <XCTest/XCTestAssertionsImpl.h>
#define ASXCTAssertEqualSizes(s0, s1, ...) \
_XCTPrimitiveAssertEqualObjects(self, NSStringFromCGSize(s0), @#s0, NSStringFromCGSize(s1), @#s1, __VA_ARGS__)
#define ASXCTAssertNotEqualSizes(s0, s1, ...) \
_XCTPrimitiveAssertNotEqualObjects(self, NSStringFromCGSize(s0), @#s0, NSStringFromCGSize(s1), @#s1, __VA_ARGS__)
#define ASXCTAssertEqualPoints(p0, p1, ...) \
_XCTPrimitiveAssertEqualObjects(self, NSStringFromCGPoint(p0), @#p0, NSStringFromCGPoint(p1), @#p1, __VA_ARGS__)
#define ASXCTAssertNotEqualPoints(p0, p1, ...) \
_XCTPrimitiveAssertNotEqualObjects(self, NSStringFromCGPoint(p0), @#p0, NSStringFromCGPoint(p1), @#p1, __VA_ARGS__)
#define ASXCTAssertEqualRects(r0, r1, ...) \
_XCTPrimitiveAssertEqualObjects(self, NSStringFromCGRect(r0), @#r0, NSStringFromCGRect(r1), @#r1, __VA_ARGS__)
#define ASXCTAssertNotEqualRects(r0, r1, ...) \
_XCTPrimitiveAssertNotEqualObjects(self, NSStringFromCGRect(r0), @#r0, NSStringFromCGRect(r1), @#r1, __VA_ARGS__)
#define ASXCTAssertEqualDimensions(r0, r1, ...) \
_XCTPrimitiveAssertEqualObjects(self, NSStringFromASDimension(r0), @#r0, NSStringFromASDimension(r1), @#r1, __VA_ARGS__)
#define ASXCTAssertNotEqualDimensions(r0, r1, ...) \
_XCTPrimitiveAssertNotEqualObjects(self, NSStringFromASDimension(r0), @#r0, NSStringFromASDimension(r1), @#r1, __VA_ARGS__)
#define ASXCTAssertEqualSizeRanges(r0, r1, ...) \
_XCTPrimitiveAssertEqualObjects(self, NSStringFromASSizeRange(r0), @#r0, NSStringFromASSizeRange(r1), @#r1, __VA_ARGS__)

View File

@@ -0,0 +1,22 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleDevelopmentRegion</key>
<string>en</string>
<key>CFBundleExecutable</key>
<string>$(EXECUTABLE_NAME)</string>
<key>CFBundleIdentifier</key>
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleName</key>
<string>$(PRODUCT_NAME)</string>
<key>CFBundlePackageType</key>
<string>BNDL</string>
<key>CFBundleShortVersionString</key>
<string>1.0</string>
<key>CFBundleVersion</key>
<string>1</string>
</dict>
</plist>

8
ASDKListKit/Podfile Normal file
View File

@@ -0,0 +1,8 @@
source 'https://github.com/CocoaPods/Specs.git'
platform :ios, '8.0'
target 'ASDKListKitTests' do
pod 'AsyncDisplayKit/IGListKit', :path => '..'
pod 'JGMethodSwizzler', :git => 'https://github.com/JonasGessner/JGMethodSwizzler', :branch => 'master'
end

View File

@@ -47,6 +47,12 @@ Pod::Spec.new do |spec|
pin.dependency 'PINRemoteImage/PINCache' pin.dependency 'PINRemoteImage/PINCache'
pin.dependency 'AsyncDisplayKit/Core' pin.dependency 'AsyncDisplayKit/Core'
end end
spec.subspec 'IGListKit' do |igl|
igl.xcconfig = { 'GCC_PREPROCESSOR_DEFINITIONS' => '$(inherited) IG_LIST_KIT=1' }
igl.dependency 'IGListKit', '2.1.0'
igl.dependency 'AsyncDisplayKit/Core'
end
# Include optional PINRemoteImage module # Include optional PINRemoteImage module
spec.default_subspec = 'PINRemoteImage' spec.default_subspec = 'PINRemoteImage'

View File

@@ -459,15 +459,30 @@
CC4C2A7A1D8902350039ACAB /* ASTraceEvent.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = CC4C2A751D88E3BF0039ACAB /* ASTraceEvent.h */; }; CC4C2A7A1D8902350039ACAB /* ASTraceEvent.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = CC4C2A751D88E3BF0039ACAB /* ASTraceEvent.h */; };
CC54A81C1D70079800296A24 /* ASDispatch.h in Headers */ = {isa = PBXBuildFile; fileRef = CC54A81B1D70077A00296A24 /* ASDispatch.h */; }; CC54A81C1D70079800296A24 /* ASDispatch.h in Headers */ = {isa = PBXBuildFile; fileRef = CC54A81B1D70077A00296A24 /* ASDispatch.h */; };
CC54A81E1D7008B300296A24 /* ASDispatchTests.m in Sources */ = {isa = PBXBuildFile; fileRef = CC54A81D1D7008B300296A24 /* ASDispatchTests.m */; }; CC54A81E1D7008B300296A24 /* ASDispatchTests.m in Sources */ = {isa = PBXBuildFile; fileRef = CC54A81D1D7008B300296A24 /* ASDispatchTests.m */; };
CC6363E21E32C00800D8A8DE /* ASCollectionInteropProtocols.h in Headers */ = {isa = PBXBuildFile; fileRef = CC6363E11E32C00800D8A8DE /* ASCollectionInteropProtocols.h */; };
CC6363E31E32C01900D8A8DE /* ASCollectionInteropProtocols.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = CC6363E11E32C00800D8A8DE /* ASCollectionInteropProtocols.h */; };
CC7FD9DF1BB5E962005CCB2B /* ASPhotosFrameworkImageRequest.m in Sources */ = {isa = PBXBuildFile; fileRef = CC7FD9DD1BB5E962005CCB2B /* ASPhotosFrameworkImageRequest.m */; }; CC7FD9DF1BB5E962005CCB2B /* ASPhotosFrameworkImageRequest.m in Sources */ = {isa = PBXBuildFile; fileRef = CC7FD9DD1BB5E962005CCB2B /* ASPhotosFrameworkImageRequest.m */; };
CC7FD9E11BB5F750005CCB2B /* ASPhotosFrameworkImageRequestTests.m in Sources */ = {isa = PBXBuildFile; fileRef = CC7FD9E01BB5F750005CCB2B /* ASPhotosFrameworkImageRequestTests.m */; }; CC7FD9E11BB5F750005CCB2B /* ASPhotosFrameworkImageRequestTests.m in Sources */ = {isa = PBXBuildFile; fileRef = CC7FD9E01BB5F750005CCB2B /* ASPhotosFrameworkImageRequestTests.m */; };
CC7FD9E21BB603FF005CCB2B /* ASPhotosFrameworkImageRequest.h in Headers */ = {isa = PBXBuildFile; fileRef = CC7FD9DC1BB5E962005CCB2B /* ASPhotosFrameworkImageRequest.h */; settings = {ATTRIBUTES = (Public, ); }; }; CC7FD9E21BB603FF005CCB2B /* ASPhotosFrameworkImageRequest.h in Headers */ = {isa = PBXBuildFile; fileRef = CC7FD9DC1BB5E962005CCB2B /* ASPhotosFrameworkImageRequest.h */; settings = {ATTRIBUTES = (Public, ); }; };
CC8525151E3FC253008EABE6 /* _ASCollectionViewCell.h in Headers */ = {isa = PBXBuildFile; fileRef = CC8525131E3FC253008EABE6 /* _ASCollectionViewCell.h */; settings = {ATTRIBUTES = (Private, ); }; };
CC8525161E3FC253008EABE6 /* _ASCollectionViewCell.m in Sources */ = {isa = PBXBuildFile; fileRef = CC8525141E3FC253008EABE6 /* _ASCollectionViewCell.m */; };
CC8525171E3FC253008EABE6 /* _ASCollectionViewCell.m in Sources */ = {isa = PBXBuildFile; fileRef = CC8525141E3FC253008EABE6 /* _ASCollectionViewCell.m */; };
CC8525181E3FC316008EABE6 /* _ASCollectionViewCell.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = CC8525131E3FC253008EABE6 /* _ASCollectionViewCell.h */; };
CC87BB951DA8193C0090E380 /* ASCellNode+Internal.h in Headers */ = {isa = PBXBuildFile; fileRef = CC87BB941DA8193C0090E380 /* ASCellNode+Internal.h */; }; CC87BB951DA8193C0090E380 /* ASCellNode+Internal.h in Headers */ = {isa = PBXBuildFile; fileRef = CC87BB941DA8193C0090E380 /* ASCellNode+Internal.h */; };
CC8B05D61D73836400F54286 /* ASPerformanceTestContext.m in Sources */ = {isa = PBXBuildFile; fileRef = CC8B05D51D73836400F54286 /* ASPerformanceTestContext.m */; }; CC8B05D61D73836400F54286 /* ASPerformanceTestContext.m in Sources */ = {isa = PBXBuildFile; fileRef = CC8B05D51D73836400F54286 /* ASPerformanceTestContext.m */; };
CC8B05D81D73979700F54286 /* ASTextNodePerformanceTests.m in Sources */ = {isa = PBXBuildFile; fileRef = CC8B05D71D73979700F54286 /* ASTextNodePerformanceTests.m */; }; CC8B05D81D73979700F54286 /* ASTextNodePerformanceTests.m in Sources */ = {isa = PBXBuildFile; fileRef = CC8B05D71D73979700F54286 /* ASTextNodePerformanceTests.m */; };
CCA221D31D6FA7EF00AF6A0F /* ASViewControllerTests.m in Sources */ = {isa = PBXBuildFile; fileRef = CCA221D21D6FA7EF00AF6A0F /* ASViewControllerTests.m */; }; CCA221D31D6FA7EF00AF6A0F /* ASViewControllerTests.m in Sources */ = {isa = PBXBuildFile; fileRef = CCA221D21D6FA7EF00AF6A0F /* ASViewControllerTests.m */; };
CCB2F34D1D63CCC6004E6DE9 /* ASDisplayNodeSnapshotTests.m in Sources */ = {isa = PBXBuildFile; fileRef = CCB2F34C1D63CCC6004E6DE9 /* ASDisplayNodeSnapshotTests.m */; }; CCB2F34D1D63CCC6004E6DE9 /* ASDisplayNodeSnapshotTests.m in Sources */ = {isa = PBXBuildFile; fileRef = CCB2F34C1D63CCC6004E6DE9 /* ASDisplayNodeSnapshotTests.m */; };
CCE04B1F1E313EA7006AEBBB /* ASSectionController.h in Headers */ = {isa = PBXBuildFile; fileRef = CCE04B1E1E313EA7006AEBBB /* ASSectionController.h */; settings = {ATTRIBUTES = (Public, ); }; };
CCE04B221E313EB9006AEBBB /* IGListAdapter+AsyncDisplayKit.h in Headers */ = {isa = PBXBuildFile; fileRef = CCE04B201E313EB9006AEBBB /* IGListAdapter+AsyncDisplayKit.h */; };
CCE04B231E313EB9006AEBBB /* IGListAdapter+AsyncDisplayKit.m in Sources */ = {isa = PBXBuildFile; fileRef = CCE04B211E313EB9006AEBBB /* IGListAdapter+AsyncDisplayKit.m */; };
CCE04B241E313EB9006AEBBB /* IGListAdapter+AsyncDisplayKit.m in Sources */ = {isa = PBXBuildFile; fileRef = CCE04B211E313EB9006AEBBB /* IGListAdapter+AsyncDisplayKit.m */; };
CCE04B2C1E314A32006AEBBB /* ASSupplementaryNodeSource.h in Headers */ = {isa = PBXBuildFile; fileRef = CCE04B2B1E314A32006AEBBB /* ASSupplementaryNodeSource.h */; settings = {ATTRIBUTES = (Public, ); }; };
CCE04B2E1E314A9C006AEBBB /* ASSectionController.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = CCE04B1E1E313EA7006AEBBB /* ASSectionController.h */; };
CCE04B2F1E314A9C006AEBBB /* ASSupplementaryNodeSource.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = CCE04B2B1E314A32006AEBBB /* ASSupplementaryNodeSource.h */; };
CCE04B301E314A9C006AEBBB /* IGListAdapter+AsyncDisplayKit.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = CCE04B201E313EB9006AEBBB /* IGListAdapter+AsyncDisplayKit.h */; };
CCF18FF41D2575E300DF5895 /* NSIndexSet+ASHelpers.h in Headers */ = {isa = PBXBuildFile; fileRef = CC4981BA1D1C7F65004E13CC /* NSIndexSet+ASHelpers.h */; }; CCF18FF41D2575E300DF5895 /* NSIndexSet+ASHelpers.h in Headers */ = {isa = PBXBuildFile; fileRef = CC4981BA1D1C7F65004E13CC /* NSIndexSet+ASHelpers.h */; };
CCF92DCD1E3155180019E9C6 /* ASIGListKitMethodImplementations.h in Headers */ = {isa = PBXBuildFile; fileRef = CCF92DCC1E3155180019E9C6 /* ASIGListKitMethodImplementations.h */; };
D785F6631A74327E00291744 /* ASScrollNode.mm in Sources */ = {isa = PBXBuildFile; fileRef = D785F6611A74327E00291744 /* ASScrollNode.mm */; }; D785F6631A74327E00291744 /* ASScrollNode.mm in Sources */ = {isa = PBXBuildFile; fileRef = D785F6611A74327E00291744 /* ASScrollNode.mm */; };
DB55C2631C6408D6004EDCF5 /* _ASTransitionContext.m in Sources */ = {isa = PBXBuildFile; fileRef = DB55C2601C6408D6004EDCF5 /* _ASTransitionContext.m */; }; DB55C2631C6408D6004EDCF5 /* _ASTransitionContext.m in Sources */ = {isa = PBXBuildFile; fileRef = DB55C2601C6408D6004EDCF5 /* _ASTransitionContext.m */; };
DB55C2671C641AE4004EDCF5 /* ASContextTransitioning.h in Headers */ = {isa = PBXBuildFile; fileRef = DB55C2651C641AE4004EDCF5 /* ASContextTransitioning.h */; settings = {ATTRIBUTES = (Public, ); }; }; DB55C2671C641AE4004EDCF5 /* ASContextTransitioning.h in Headers */ = {isa = PBXBuildFile; fileRef = DB55C2651C641AE4004EDCF5 /* ASContextTransitioning.h */; settings = {ATTRIBUTES = (Public, ); }; };
@@ -674,6 +689,7 @@
dstPath = "include/$(PRODUCT_NAME)"; dstPath = "include/$(PRODUCT_NAME)";
dstSubfolderSpec = 16; dstSubfolderSpec = 16;
files = ( files = (
CC8525181E3FC316008EABE6 /* _ASCollectionViewCell.h in CopyFiles */,
690ED59D1E36D140000627C0 /* ASImageNode+tvOS.h in CopyFiles */, 690ED59D1E36D140000627C0 /* ASImageNode+tvOS.h in CopyFiles */,
690ED59C1E36D13A000627C0 /* ASControlNode+tvOS.h in CopyFiles */, 690ED59C1E36D13A000627C0 /* ASControlNode+tvOS.h in CopyFiles */,
690ED58F1E36BCBF000627C0 /* ASLayoutElementStylePrivate.h in CopyFiles */, 690ED58F1E36BCBF000627C0 /* ASLayoutElementStylePrivate.h in CopyFiles */,
@@ -682,6 +698,10 @@
692BE8D81E36B66500C86D87 /* ASLayoutSpecPrivate.h in CopyFiles */, 692BE8D81E36B66500C86D87 /* ASLayoutSpecPrivate.h in CopyFiles */,
6947B0C71E36B5B60007C478 /* ASStackPositionedLayout.h in CopyFiles */, 6947B0C71E36B5B60007C478 /* ASStackPositionedLayout.h in CopyFiles */,
6947B0C61E36B5A90007C478 /* ASStackUnpositionedLayout.h in CopyFiles */, 6947B0C61E36B5A90007C478 /* ASStackUnpositionedLayout.h in CopyFiles */,
CC6363E31E32C01900D8A8DE /* ASCollectionInteropProtocols.h in CopyFiles */,
CCE04B2E1E314A9C006AEBBB /* ASSectionController.h in CopyFiles */,
CCE04B2F1E314A9C006AEBBB /* ASSupplementaryNodeSource.h in CopyFiles */,
CCE04B301E314A9C006AEBBB /* IGListAdapter+AsyncDisplayKit.h in CopyFiles */,
693DA5141E25373100F66DF4 /* ASDimensionDeprecated.h in CopyFiles */, 693DA5141E25373100F66DF4 /* ASDimensionDeprecated.h in CopyFiles */,
693DA50F1E2536A600F66DF4 /* ASDimensionInternal.h in CopyFiles */, 693DA50F1E2536A600F66DF4 /* ASDimensionInternal.h in CopyFiles */,
68C2155C1DE11AA80019C4BC /* ASObjectDescriptionHelpers.h in CopyFiles */, 68C2155C1DE11AA80019C4BC /* ASObjectDescriptionHelpers.h in CopyFiles */,
@@ -967,7 +987,7 @@
257754BC1BEE458E00737CA5 /* ASTextNodeTypes.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ASTextNodeTypes.h; path = TextKit/ASTextNodeTypes.h; sourceTree = "<group>"; }; 257754BC1BEE458E00737CA5 /* ASTextNodeTypes.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ASTextNodeTypes.h; path = TextKit/ASTextNodeTypes.h; sourceTree = "<group>"; };
257754BD1BEE458E00737CA5 /* ASTextNodeWordKerner.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = ASTextNodeWordKerner.m; path = TextKit/ASTextNodeWordKerner.m; sourceTree = "<group>"; }; 257754BD1BEE458E00737CA5 /* ASTextNodeWordKerner.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = ASTextNodeWordKerner.m; path = TextKit/ASTextNodeWordKerner.m; sourceTree = "<group>"; };
25E327541C16819500A2170C /* ASPagerNode.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; lineEnding = 0; path = ASPagerNode.h; sourceTree = "<group>"; }; 25E327541C16819500A2170C /* ASPagerNode.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; lineEnding = 0; path = ASPagerNode.h; sourceTree = "<group>"; };
25E327551C16819500A2170C /* ASPagerNode.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; lineEnding = 0; path = ASPagerNode.m; sourceTree = "<group>"; xcLanguageSpecificationIdentifier = xcode.lang.objc; }; 25E327551C16819500A2170C /* ASPagerNode.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; lineEnding = 0; path = ASPagerNode.m; sourceTree = "<group>"; };
2911485B1A77147A005D0878 /* ASControlNodeTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ASControlNodeTests.m; sourceTree = "<group>"; }; 2911485B1A77147A005D0878 /* ASControlNodeTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ASControlNodeTests.m; sourceTree = "<group>"; };
292C59991A956527007E5DD6 /* ASLayoutRangeType.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ASLayoutRangeType.h; sourceTree = "<group>"; }; 292C59991A956527007E5DD6 /* ASLayoutRangeType.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ASLayoutRangeType.h; sourceTree = "<group>"; };
2967F9E11AB0A4CF0072E4AB /* ASBasicImageDownloaderInternal.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ASBasicImageDownloaderInternal.h; sourceTree = "<group>"; }; 2967F9E11AB0A4CF0072E4AB /* ASBasicImageDownloaderInternal.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ASBasicImageDownloaderInternal.h; sourceTree = "<group>"; };
@@ -1158,15 +1178,23 @@
CC512B841DAC45C60054848E /* ASTableView+Undeprecated.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "ASTableView+Undeprecated.h"; sourceTree = "<group>"; }; CC512B841DAC45C60054848E /* ASTableView+Undeprecated.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "ASTableView+Undeprecated.h"; sourceTree = "<group>"; };
CC54A81B1D70077A00296A24 /* ASDispatch.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ASDispatch.h; sourceTree = "<group>"; }; CC54A81B1D70077A00296A24 /* ASDispatch.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ASDispatch.h; sourceTree = "<group>"; };
CC54A81D1D7008B300296A24 /* ASDispatchTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ASDispatchTests.m; sourceTree = "<group>"; }; CC54A81D1D7008B300296A24 /* ASDispatchTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ASDispatchTests.m; sourceTree = "<group>"; };
CC6363E11E32C00800D8A8DE /* ASCollectionInteropProtocols.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ASCollectionInteropProtocols.h; sourceTree = "<group>"; };
CC7FD9DC1BB5E962005CCB2B /* ASPhotosFrameworkImageRequest.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ASPhotosFrameworkImageRequest.h; sourceTree = "<group>"; }; CC7FD9DC1BB5E962005CCB2B /* ASPhotosFrameworkImageRequest.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ASPhotosFrameworkImageRequest.h; sourceTree = "<group>"; };
CC7FD9DD1BB5E962005CCB2B /* ASPhotosFrameworkImageRequest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ASPhotosFrameworkImageRequest.m; sourceTree = "<group>"; }; CC7FD9DD1BB5E962005CCB2B /* ASPhotosFrameworkImageRequest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ASPhotosFrameworkImageRequest.m; sourceTree = "<group>"; };
CC7FD9E01BB5F750005CCB2B /* ASPhotosFrameworkImageRequestTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ASPhotosFrameworkImageRequestTests.m; sourceTree = "<group>"; }; CC7FD9E01BB5F750005CCB2B /* ASPhotosFrameworkImageRequestTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ASPhotosFrameworkImageRequestTests.m; sourceTree = "<group>"; };
CC8525131E3FC253008EABE6 /* _ASCollectionViewCell.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = _ASCollectionViewCell.h; sourceTree = "<group>"; };
CC8525141E3FC253008EABE6 /* _ASCollectionViewCell.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = _ASCollectionViewCell.m; sourceTree = "<group>"; };
CC87BB941DA8193C0090E380 /* ASCellNode+Internal.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = "ASCellNode+Internal.h"; path = "AsyncDisplayKit/ASCellNode+Internal.h"; sourceTree = SOURCE_ROOT; }; CC87BB941DA8193C0090E380 /* ASCellNode+Internal.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = "ASCellNode+Internal.h"; path = "AsyncDisplayKit/ASCellNode+Internal.h"; sourceTree = SOURCE_ROOT; };
CC8B05D41D73836400F54286 /* ASPerformanceTestContext.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ASPerformanceTestContext.h; sourceTree = "<group>"; }; CC8B05D41D73836400F54286 /* ASPerformanceTestContext.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ASPerformanceTestContext.h; sourceTree = "<group>"; };
CC8B05D51D73836400F54286 /* ASPerformanceTestContext.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ASPerformanceTestContext.m; sourceTree = "<group>"; }; CC8B05D51D73836400F54286 /* ASPerformanceTestContext.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ASPerformanceTestContext.m; sourceTree = "<group>"; };
CC8B05D71D73979700F54286 /* ASTextNodePerformanceTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ASTextNodePerformanceTests.m; sourceTree = "<group>"; }; CC8B05D71D73979700F54286 /* ASTextNodePerformanceTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ASTextNodePerformanceTests.m; sourceTree = "<group>"; };
CCA221D21D6FA7EF00AF6A0F /* ASViewControllerTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ASViewControllerTests.m; sourceTree = "<group>"; }; CCA221D21D6FA7EF00AF6A0F /* ASViewControllerTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ASViewControllerTests.m; sourceTree = "<group>"; };
CCB2F34C1D63CCC6004E6DE9 /* ASDisplayNodeSnapshotTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ASDisplayNodeSnapshotTests.m; sourceTree = "<group>"; }; CCB2F34C1D63CCC6004E6DE9 /* ASDisplayNodeSnapshotTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ASDisplayNodeSnapshotTests.m; sourceTree = "<group>"; };
CCE04B1E1E313EA7006AEBBB /* ASSectionController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ASSectionController.h; sourceTree = "<group>"; };
CCE04B201E313EB9006AEBBB /* IGListAdapter+AsyncDisplayKit.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "IGListAdapter+AsyncDisplayKit.h"; sourceTree = "<group>"; };
CCE04B211E313EB9006AEBBB /* IGListAdapter+AsyncDisplayKit.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "IGListAdapter+AsyncDisplayKit.m"; sourceTree = "<group>"; };
CCE04B2B1E314A32006AEBBB /* ASSupplementaryNodeSource.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ASSupplementaryNodeSource.h; sourceTree = "<group>"; };
CCF92DCC1E3155180019E9C6 /* ASIGListKitMethodImplementations.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ASIGListKitMethodImplementations.h; sourceTree = "<group>"; };
D3779BCFF841AD3EB56537ED /* Pods-AsyncDisplayKitTests.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-AsyncDisplayKitTests.release.xcconfig"; path = "Pods/Target Support Files/Pods-AsyncDisplayKitTests/Pods-AsyncDisplayKitTests.release.xcconfig"; sourceTree = "<group>"; }; D3779BCFF841AD3EB56537ED /* Pods-AsyncDisplayKitTests.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-AsyncDisplayKitTests.release.xcconfig"; path = "Pods/Target Support Files/Pods-AsyncDisplayKitTests/Pods-AsyncDisplayKitTests.release.xcconfig"; sourceTree = "<group>"; };
D785F6601A74327E00291744 /* ASScrollNode.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ASScrollNode.h; sourceTree = "<group>"; }; D785F6601A74327E00291744 /* ASScrollNode.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ASScrollNode.h; sourceTree = "<group>"; };
D785F6611A74327E00291744 /* ASScrollNode.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = ASScrollNode.mm; sourceTree = "<group>"; }; D785F6611A74327E00291744 /* ASScrollNode.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = ASScrollNode.mm; sourceTree = "<group>"; };
@@ -1316,6 +1344,7 @@
058D09B1195D04C000B7D73C /* AsyncDisplayKit */ = { 058D09B1195D04C000B7D73C /* AsyncDisplayKit */ = {
isa = PBXGroup; isa = PBXGroup;
children = ( children = (
CCE04B1D1E313E99006AEBBB /* Collection Data Adapter */,
DBDB83921C6E879900D0098C /* ASPagerFlowLayout.h */, DBDB83921C6E879900D0098C /* ASPagerFlowLayout.h */,
DBDB83931C6E879900D0098C /* ASPagerFlowLayout.m */, DBDB83931C6E879900D0098C /* ASPagerFlowLayout.m */,
92DD2FE11BF4B97E0074C9DD /* ASMapNode.h */, 92DD2FE11BF4B97E0074C9DD /* ASMapNode.h */,
@@ -1485,6 +1514,8 @@
058D09E1195D050800B7D73C /* Details */ = { 058D09E1195D050800B7D73C /* Details */ = {
isa = PBXGroup; isa = PBXGroup;
children = ( children = (
CC8525131E3FC253008EABE6 /* _ASCollectionViewCell.h */,
CC8525141E3FC253008EABE6 /* _ASCollectionViewCell.m */,
058D09E2195D050800B7D73C /* _ASDisplayLayer.h */, 058D09E2195D050800B7D73C /* _ASDisplayLayer.h */,
058D09E3195D050800B7D73C /* _ASDisplayLayer.mm */, 058D09E3195D050800B7D73C /* _ASDisplayLayer.mm */,
058D09E4195D050800B7D73C /* _ASDisplayView.h */, 058D09E4195D050800B7D73C /* _ASDisplayView.h */,
@@ -1577,6 +1608,7 @@
isa = PBXGroup; isa = PBXGroup;
children = ( children = (
6947B0BB1E36B4E30007C478 /* Layout */, 6947B0BB1E36B4E30007C478 /* Layout */,
CCE04B2A1E313EDA006AEBBB /* Collection Data Adapter */,
058D0A03195D050800B7D73C /* _ASCoreAnimationExtras.h */, 058D0A03195D050800B7D73C /* _ASCoreAnimationExtras.h */,
058D0A04195D050800B7D73C /* _ASCoreAnimationExtras.mm */, 058D0A04195D050800B7D73C /* _ASCoreAnimationExtras.mm */,
AC026B6D1BD57DBF00BBC17E /* _ASHierarchyChangeSet.h */, AC026B6D1BD57DBF00BBC17E /* _ASHierarchyChangeSet.h */,
@@ -1784,6 +1816,34 @@
name = "Supporting Files"; name = "Supporting Files";
sourceTree = "<group>"; sourceTree = "<group>";
}; };
CCE04B1D1E313E99006AEBBB /* Collection Data Adapter */ = {
isa = PBXGroup;
children = (
CCE04B1E1E313EA7006AEBBB /* ASSectionController.h */,
CCE04B2B1E314A32006AEBBB /* ASSupplementaryNodeSource.h */,
CCF92DCE1E315FC50019E9C6 /* IGListKit Support */,
);
name = "Collection Data Adapter";
sourceTree = "<group>";
};
CCE04B2A1E313EDA006AEBBB /* Collection Data Adapter */ = {
isa = PBXGroup;
children = (
CC6363E11E32C00800D8A8DE /* ASCollectionInteropProtocols.h */,
);
name = "Collection Data Adapter";
sourceTree = "<group>";
};
CCF92DCE1E315FC50019E9C6 /* IGListKit Support */ = {
isa = PBXGroup;
children = (
CCF92DCC1E3155180019E9C6 /* ASIGListKitMethodImplementations.h */,
CCE04B201E313EB9006AEBBB /* IGListAdapter+AsyncDisplayKit.h */,
CCE04B211E313EB9006AEBBB /* IGListAdapter+AsyncDisplayKit.m */,
);
name = "IGListKit Support";
sourceTree = "<group>";
};
DE89C1691DCEB9CC00D49D74 /* Debug */ = { DE89C1691DCEB9CC00D49D74 /* Debug */ = {
isa = PBXGroup; isa = PBXGroup;
children = ( children = (
@@ -1855,11 +1915,13 @@
254C6B731BF94DF4003EC431 /* ASTextKitCoreTextAdditions.h in Headers */, 254C6B731BF94DF4003EC431 /* ASTextKitCoreTextAdditions.h in Headers */,
A2763D7A1CBDD57D00A9ADBD /* ASPINRemoteImageDownloader.h in Headers */, A2763D7A1CBDD57D00A9ADBD /* ASPINRemoteImageDownloader.h in Headers */,
254C6B7A1BF94DF4003EC431 /* ASTextKitRenderer.h in Headers */, 254C6B7A1BF94DF4003EC431 /* ASTextKitRenderer.h in Headers */,
CCE04B1F1E313EA7006AEBBB /* ASSectionController.h in Headers */,
69CB62AC1CB8165900024920 /* _ASDisplayViewAccessiblity.h in Headers */, 69CB62AC1CB8165900024920 /* _ASDisplayViewAccessiblity.h in Headers */,
68355B3F1CB57A64001D4E68 /* ASPINRemoteImageDownloader.h in Headers */, 68355B3F1CB57A64001D4E68 /* ASPINRemoteImageDownloader.h in Headers */,
254C6B7C1BF94DF4003EC431 /* ASTextKitRenderer+TextChecking.h in Headers */, 254C6B7C1BF94DF4003EC431 /* ASTextKitRenderer+TextChecking.h in Headers */,
34EFC7611B701C9C00AD841F /* ASBackgroundLayoutSpec.h in Headers */, 34EFC7611B701C9C00AD841F /* ASBackgroundLayoutSpec.h in Headers */,
68AF37DB1CBEF4D80077BF76 /* ASImageNode+AnimatedImagePrivate.h in Headers */, 68AF37DB1CBEF4D80077BF76 /* ASImageNode+AnimatedImagePrivate.h in Headers */,
CCE04B221E313EB9006AEBBB /* IGListAdapter+AsyncDisplayKit.h in Headers */,
B35062591B010F070018CF92 /* ASBaseDefines.h in Headers */, B35062591B010F070018CF92 /* ASBaseDefines.h in Headers */,
B35062131B010EFD0018CF92 /* ASBasicImageDownloader.h in Headers */, B35062131B010EFD0018CF92 /* ASBasicImageDownloader.h in Headers */,
B35062461B010EFD0018CF92 /* ASBasicImageDownloaderInternal.h in Headers */, B35062461B010EFD0018CF92 /* ASBasicImageDownloaderInternal.h in Headers */,
@@ -1883,6 +1945,7 @@
9C70F20F1CDBE9FF007D6C76 /* ASLayoutManager.h in Headers */, 9C70F20F1CDBE9FF007D6C76 /* ASLayoutManager.h in Headers */,
B35061FA1B010EFD0018CF92 /* ASControlNode+Subclasses.h in Headers */, B35061FA1B010EFD0018CF92 /* ASControlNode+Subclasses.h in Headers */,
6947B0C31E36B5040007C478 /* ASStackPositionedLayout.h in Headers */, 6947B0C31E36B5040007C478 /* ASStackPositionedLayout.h in Headers */,
CC6363E21E32C00800D8A8DE /* ASCollectionInteropProtocols.h in Headers */,
B35061F81B010EFD0018CF92 /* ASControlNode.h in Headers */, B35061F81B010EFD0018CF92 /* ASControlNode.h in Headers */,
B35062171B010EFD0018CF92 /* ASDataController.h in Headers */, B35062171B010EFD0018CF92 /* ASDataController.h in Headers */,
34EFC75B1B701BAF00AD841F /* ASDimension.h in Headers */, 34EFC75B1B701BAF00AD841F /* ASDimension.h in Headers */,
@@ -1901,6 +1964,7 @@
B350621B1B010EFD0018CF92 /* ASFlowLayoutController.h in Headers */, B350621B1B010EFD0018CF92 /* ASFlowLayoutController.h in Headers */,
B350621D1B010EFD0018CF92 /* ASHighlightOverlayLayer.h in Headers */, B350621D1B010EFD0018CF92 /* ASHighlightOverlayLayer.h in Headers */,
C78F7E2B1BF7809800CDEAFC /* ASTableNode.h in Headers */, C78F7E2B1BF7809800CDEAFC /* ASTableNode.h in Headers */,
CCF92DCD1E3155180019E9C6 /* ASIGListKitMethodImplementations.h in Headers */,
AC7A2C181BDE11DF0093FE1A /* ASTableViewInternal.h in Headers */, AC7A2C181BDE11DF0093FE1A /* ASTableViewInternal.h in Headers */,
B35062531B010EFD0018CF92 /* ASImageNode+CGExtras.h in Headers */, B35062531B010EFD0018CF92 /* ASImageNode+CGExtras.h in Headers */,
254C6B7F1BF94DF4003EC431 /* ASTextKitTruncating.h in Headers */, 254C6B7F1BF94DF4003EC431 /* ASTextKitTruncating.h in Headers */,
@@ -1935,6 +1999,7 @@
DECBD6E81BE56E1900CF4905 /* ASButtonNode.h in Headers */, DECBD6E81BE56E1900CF4905 /* ASButtonNode.h in Headers */,
B35062241B010EFD0018CF92 /* ASMutableAttributedStringBuilder.h in Headers */, B35062241B010EFD0018CF92 /* ASMutableAttributedStringBuilder.h in Headers */,
B13CA0F81C519EBA00E031AB /* ASCollectionViewLayoutFacilitatorProtocol.h in Headers */, B13CA0F81C519EBA00E031AB /* ASCollectionViewLayoutFacilitatorProtocol.h in Headers */,
CCE04B2C1E314A32006AEBBB /* ASSupplementaryNodeSource.h in Headers */,
8BBBAB8C1CEBAF1700107FC6 /* ASDefaultPlaybackButton.h in Headers */, 8BBBAB8C1CEBAF1700107FC6 /* ASDefaultPlaybackButton.h in Headers */,
B35062061B010EFD0018CF92 /* ASNetworkImageNode.h in Headers */, B35062061B010EFD0018CF92 /* ASNetworkImageNode.h in Headers */,
34EFC76C1B701CED00AD841F /* ASOverlayLayoutSpec.h in Headers */, 34EFC76C1B701CED00AD841F /* ASOverlayLayoutSpec.h in Headers */,
@@ -1973,6 +2038,7 @@
9C6BB3B31B8CC9C200F13F52 /* ASAbsoluteLayoutElement.h in Headers */, 9C6BB3B31B8CC9C200F13F52 /* ASAbsoluteLayoutElement.h in Headers */,
34EFC7731B701D0700AD841F /* ASAbsoluteLayoutSpec.h in Headers */, 34EFC7731B701D0700AD841F /* ASAbsoluteLayoutSpec.h in Headers */,
254C6B781BF94DF4003EC431 /* ASTextKitContext.h in Headers */, 254C6B781BF94DF4003EC431 /* ASTextKitContext.h in Headers */,
CC8525151E3FC253008EABE6 /* _ASCollectionViewCell.h in Headers */,
B350620A1B010EFD0018CF92 /* ASTableView.h in Headers */, B350620A1B010EFD0018CF92 /* ASTableView.h in Headers */,
B350620C1B010EFD0018CF92 /* ASTableViewProtocols.h in Headers */, B350620C1B010EFD0018CF92 /* ASTableViewProtocols.h in Headers */,
B350620D1B010EFD0018CF92 /* ASTextNode.h in Headers */, B350620D1B010EFD0018CF92 /* ASTextNode.h in Headers */,
@@ -2227,6 +2293,7 @@
AC6456091B0A335000CF11B8 /* ASCellNode.mm in Sources */, AC6456091B0A335000CF11B8 /* ASCellNode.mm in Sources */,
DE8BEAC31C2DF3FC00D57C12 /* ASDelegateProxy.m in Sources */, DE8BEAC31C2DF3FC00D57C12 /* ASDelegateProxy.m in Sources */,
ACF6ED1D1B17843500DA7C62 /* ASCenterLayoutSpec.mm in Sources */, ACF6ED1D1B17843500DA7C62 /* ASCenterLayoutSpec.mm in Sources */,
CC8525161E3FC253008EABE6 /* _ASCollectionViewCell.m in Sources */,
9F98C0251DBDF2A300476D92 /* ASControlTargetAction.m in Sources */, 9F98C0251DBDF2A300476D92 /* ASControlTargetAction.m in Sources */,
18C2ED801B9B7DE800F627B3 /* ASCollectionNode.mm in Sources */, 18C2ED801B9B7DE800F627B3 /* ASCollectionNode.mm in Sources */,
92DD2FE41BF4B97E0074C9DD /* ASMapNode.mm in Sources */, 92DD2FE41BF4B97E0074C9DD /* ASMapNode.mm in Sources */,
@@ -2274,6 +2341,7 @@
AC6145431D8AFD4F003D62A2 /* ASSection.m in Sources */, AC6145431D8AFD4F003D62A2 /* ASSection.m in Sources */,
058D0A1B195D050800B7D73C /* ASMutableAttributedStringBuilder.m in Sources */, 058D0A1B195D050800B7D73C /* ASMutableAttributedStringBuilder.m in Sources */,
055B9FA91A1C154B00035D6D /* ASNetworkImageNode.mm in Sources */, 055B9FA91A1C154B00035D6D /* ASNetworkImageNode.mm in Sources */,
CCE04B231E313EB9006AEBBB /* IGListAdapter+AsyncDisplayKit.m in Sources */,
AEB7B01B1C5962EA00662EF4 /* ASDefaultPlayButton.m in Sources */, AEB7B01B1C5962EA00662EF4 /* ASDefaultPlayButton.m in Sources */,
CC3B20851C3F76D600798563 /* ASPendingStateController.mm in Sources */, CC3B20851C3F76D600798563 /* ASPendingStateController.mm in Sources */,
ACF6ED2C1B17843500DA7C62 /* ASOverlayLayoutSpec.mm in Sources */, ACF6ED2C1B17843500DA7C62 /* ASOverlayLayoutSpec.mm in Sources */,
@@ -2418,6 +2486,7 @@
DE8BEAC41C2DF3FC00D57C12 /* ASDelegateProxy.m in Sources */, DE8BEAC41C2DF3FC00D57C12 /* ASDelegateProxy.m in Sources */,
9C70F2081CDAA3C6007D6C76 /* ASEnvironment.mm in Sources */, 9C70F2081CDAA3C6007D6C76 /* ASEnvironment.mm in Sources */,
B35062141B010EFD0018CF92 /* ASBasicImageDownloader.mm in Sources */, B35062141B010EFD0018CF92 /* ASBasicImageDownloader.mm in Sources */,
CC8525171E3FC253008EABE6 /* _ASCollectionViewCell.m in Sources */,
B35062161B010EFD0018CF92 /* ASBatchContext.mm in Sources */, B35062161B010EFD0018CF92 /* ASBatchContext.mm in Sources */,
AC47D9421B3B891B00AAEE9D /* ASCellNode.mm in Sources */, AC47D9421B3B891B00AAEE9D /* ASCellNode.mm in Sources */,
34EFC7641B701CC600AD841F /* ASCenterLayoutSpec.mm in Sources */, 34EFC7641B701CC600AD841F /* ASCenterLayoutSpec.mm in Sources */,
@@ -2465,6 +2534,7 @@
34EFC7681B701CDE00AD841F /* ASLayout.mm in Sources */, 34EFC7681B701CDE00AD841F /* ASLayout.mm in Sources */,
DECBD6EA1BE56E1900CF4905 /* ASButtonNode.mm in Sources */, DECBD6EA1BE56E1900CF4905 /* ASButtonNode.mm in Sources */,
254C6B841BF94F8A003EC431 /* ASTextNodeWordKerner.m in Sources */, 254C6B841BF94F8A003EC431 /* ASTextNodeWordKerner.m in Sources */,
CCE04B241E313EB9006AEBBB /* IGListAdapter+AsyncDisplayKit.m in Sources */,
34EFC76B1B701CEB00AD841F /* ASLayoutSpec.mm in Sources */, 34EFC76B1B701CEB00AD841F /* ASLayoutSpec.mm in Sources */,
CC3B20861C3F76D600798563 /* ASPendingStateController.mm in Sources */, CC3B20861C3F76D600798563 /* ASPendingStateController.mm in Sources */,
254C6B8C1BF94F8A003EC431 /* ASTextKitTailTruncater.mm in Sources */, 254C6B8C1BF94F8A003EC431 /* ASTextKitTailTruncater.mm in Sources */,

View File

@@ -501,6 +501,16 @@ NS_ASSUME_NONNULL_BEGIN
*/ */
- (nullable id<ASSectionContext>)collectionNode:(ASCollectionNode *)collectionNode contextForSection:(NSInteger)section; - (nullable id<ASSectionContext>)collectionNode:(ASCollectionNode *)collectionNode contextForSection:(NSInteger)section;
/**
* Asks the data source to provide an array of supplementary element kinds that exist in a given section.
*
* @param collectionNode The sender.
* @param section The index of the section to provide supplementary kinds for.
*
* @return The supplementary element kinds that exist in the given section, if any.
*/
- (NSArray<NSString *> *)collectionNode:(ASCollectionNode *)collectionNode supplementaryElementKindsInSection:(NSInteger)section;
/** /**
* Similar to -collectionView:cellForItemAtIndexPath:. * Similar to -collectionView:cellForItemAtIndexPath:.
* *

View File

@@ -13,6 +13,7 @@
#import "ASCollectionInternal.h" #import "ASCollectionInternal.h"
#import "ASCollectionViewLayoutFacilitatorProtocol.h" #import "ASCollectionViewLayoutFacilitatorProtocol.h"
#import "ASCollectionNode.h" #import "ASCollectionNode.h"
#import "ASCollectionNode+Beta.h"
#import "ASDisplayNode+Subclasses.h" #import "ASDisplayNode+Subclasses.h"
#import "ASDisplayNode+FrameworkPrivate.h" #import "ASDisplayNode+FrameworkPrivate.h"
#import "ASEnvironmentInternal.h" #import "ASEnvironmentInternal.h"

View File

@@ -8,12 +8,18 @@
// of patent rights can be found in the PATENTS file in the same directory. // of patent rights can be found in the PATENTS file in the same directory.
// //
#import "ASCollectionView.h"
#import <objc/runtime.h>
#import "_ASCollectionViewCell.h"
#import "ASAssert.h" #import "ASAssert.h"
#import "ASAvailability.h" #import "ASAvailability.h"
#import "ASBatchFetching.h" #import "ASBatchFetching.h"
#import "ASDelegateProxy.h" #import "ASDelegateProxy.h"
#import "ASCellNode+Internal.h" #import "ASCellNode+Internal.h"
#import "ASCollectionDataController.h" #import "ASCollectionDataController.h"
#import "ASCollectionInternal.h"
#import "ASCollectionViewLayoutController.h" #import "ASCollectionViewLayoutController.h"
#import "ASCollectionViewFlowLayoutInspector.h" #import "ASCollectionViewFlowLayoutInspector.h"
#import "ASDisplayNodeExtras.h" #import "ASDisplayNodeExtras.h"
@@ -27,6 +33,7 @@
#import "ASSectionContext.h" #import "ASSectionContext.h"
#import "ASCollectionView+Undeprecated.h" #import "ASCollectionView+Undeprecated.h"
#import "_ASHierarchyChangeSet.h" #import "_ASHierarchyChangeSet.h"
#import "ASCollectionInteropProtocols.h"
/** /**
* A macro to get self.collectionNode and assign it to a local variable, or return * A macro to get self.collectionNode and assign it to a local variable, or return
@@ -62,79 +69,6 @@ static const NSUInteger kASCollectionViewAnimationNone = UITableViewRowAnimation
/// Used for all cells and supplementaries. UICV keys by supp-kind+reuseID so this is plenty. /// Used for all cells and supplementaries. UICV keys by supp-kind+reuseID so this is plenty.
static NSString * const kReuseIdentifier = @"_ASCollectionReuseIdentifier"; static NSString * const kReuseIdentifier = @"_ASCollectionReuseIdentifier";
#pragma mark -
#pragma mark ASCellNode<->UICollectionViewCell bridging.
@class _ASCollectionViewCell;
@interface _ASCollectionViewCell : UICollectionViewCell
@property (nonatomic, weak) ASCellNode *node;
@property (nonatomic, strong) UICollectionViewLayoutAttributes *layoutAttributes;
@end
@implementation _ASCollectionViewCell
- (void)setNode:(ASCellNode *)node
{
ASDisplayNodeAssertMainThread();
node.layoutAttributes = _layoutAttributes;
_node = node;
self.backgroundColor = node.backgroundColor;
self.clipsToBounds = node.clipsToBounds;
[node __setSelectedFromUIKit:self.selected];
[node __setHighlightedFromUIKit:self.highlighted];
}
- (void)setSelected:(BOOL)selected
{
[super setSelected:selected];
[_node __setSelectedFromUIKit:selected];
}
- (void)setHighlighted:(BOOL)highlighted
{
[super setHighlighted:highlighted];
[_node __setHighlightedFromUIKit:highlighted];
}
- (void)setLayoutAttributes:(UICollectionViewLayoutAttributes *)layoutAttributes
{
_layoutAttributes = layoutAttributes;
_node.layoutAttributes = layoutAttributes;
}
- (void)prepareForReuse
{
self.layoutAttributes = nil;
// Need to clear node pointer before UIKit calls setSelected:NO / setHighlighted:NO on its cells
self.node = nil;
[super prepareForReuse];
}
/**
* In the initial case, this is called by UICollectionView during cell dequeueing, before
* we get a chance to assign a node to it, so we must be sure to set these layout attributes
* on our node when one is next assigned to us in @c setNode: . Since there may be cases when we _do_ already
* have our node assigned e.g. during a layout update for existing cells, we also attempt
* to update it now.
*/
- (void)applyLayoutAttributes:(UICollectionViewLayoutAttributes *)layoutAttributes
{
self.layoutAttributes = layoutAttributes;
}
/**
* Keep our node filling our content view.
*/
- (void)layoutSubviews
{
[super layoutSubviews];
self.node.frame = self.contentView.bounds;
}
@end
#pragma mark - #pragma mark -
#pragma mark ASCollectionView. #pragma mark ASCollectionView.
@@ -243,8 +177,9 @@ static NSString * const kReuseIdentifier = @"_ASCollectionReuseIdentifier";
unsigned int collectionNodeWillBeginBatchFetch:1; unsigned int collectionNodeWillBeginBatchFetch:1;
unsigned int collectionNodeWillDisplaySupplementaryElement:1; unsigned int collectionNodeWillDisplaySupplementaryElement:1;
unsigned int collectionNodeDidEndDisplayingSupplementaryElement:1; unsigned int collectionNodeDidEndDisplayingSupplementaryElement:1;
unsigned int shouldBatchFetchForCollectionNode:1; unsigned int shouldBatchFetchForCollectionNode:1;
// Whether this delegate conforms to ASCollectionDataSourceInterop
unsigned int interop:1;
} _asyncDelegateFlags; } _asyncDelegateFlags;
struct { struct {
@@ -256,9 +191,13 @@ static NSString * const kReuseIdentifier = @"_ASCollectionReuseIdentifier";
unsigned int collectionNodeNodeForItem:1; unsigned int collectionNodeNodeForItem:1;
unsigned int collectionNodeNodeBlockForItem:1; unsigned int collectionNodeNodeBlockForItem:1;
unsigned int collectionNodeNodeForSupplementaryElement:1; unsigned int collectionNodeNodeForSupplementaryElement:1;
unsigned int collectionNodeSupplementaryElementKindsInSection:1;
unsigned int numberOfSectionsInCollectionNode:1; unsigned int numberOfSectionsInCollectionNode:1;
unsigned int collectionNodeNumberOfItemsInSection:1; unsigned int collectionNodeNumberOfItemsInSection:1;
unsigned int collectionNodeContextForSection:1; unsigned int collectionNodeContextForSection:1;
// Whether this data source conforms to ASCollectionDataSourceInterop
unsigned int interop:1;
} _asyncDataSourceFlags; } _asyncDataSourceFlags;
struct { struct {
@@ -267,8 +206,6 @@ static NSString * const kReuseIdentifier = @"_ASCollectionReuseIdentifier";
} _layoutInspectorFlags; } _layoutInspectorFlags;
} }
@property (nonatomic, weak) ASCollectionNode *collectionNode;
@end @end
@interface ASCollectionNode () @interface ASCollectionNode ()
@@ -426,14 +363,14 @@ static NSString * const kReuseIdentifier = @"_ASCollectionReuseIdentifier";
- (void)setDataSource:(id<UICollectionViewDataSource>)dataSource - (void)setDataSource:(id<UICollectionViewDataSource>)dataSource
{ {
// UIKit can internally generate a call to this method upon changing the asyncDataSource; only assert for non-nil. // UIKit can internally generate a call to this method upon changing the asyncDataSource; only assert for non-nil. We also allow this when we're doing interop.
ASDisplayNodeAssert(dataSource == nil, @"ASCollectionView uses asyncDataSource, not UICollectionView's dataSource property."); ASDisplayNodeAssert(_asyncDelegateFlags.interop || dataSource == nil, @"ASCollectionView uses asyncDataSource, not UICollectionView's dataSource property.");
} }
- (void)setDelegate:(id<UICollectionViewDelegate>)delegate - (void)setDelegate:(id<UICollectionViewDelegate>)delegate
{ {
// Our UIScrollView superclass sets its delegate to nil on dealloc. Only assert if we get a non-nil value here. // Our UIScrollView superclass sets its delegate to nil on dealloc. Only assert if we get a non-nil value here. We also allow this when we're doing interop.
ASDisplayNodeAssert(delegate == nil, @"ASCollectionView uses asyncDelegate, not UICollectionView's delegate property."); ASDisplayNodeAssert(_asyncDelegateFlags.interop || delegate == nil, @"ASCollectionView uses asyncDelegate, not UICollectionView's delegate property.");
} }
- (void)proxyTargetHasDeallocated:(ASDelegateProxy *)proxy - (void)proxyTargetHasDeallocated:(ASDelegateProxy *)proxy
@@ -464,8 +401,8 @@ static NSString * const kReuseIdentifier = @"_ASCollectionReuseIdentifier";
if (asyncDataSource == nil) { if (asyncDataSource == nil) {
_asyncDataSource = nil; _asyncDataSource = nil;
_proxyDataSource = _isDeallocating ? nil : [[ASCollectionViewProxy alloc] initWithTarget:nil interceptor:self]; _proxyDataSource = _isDeallocating ? nil : [[ASCollectionViewProxy alloc] initWithTarget:nil interceptor:self];
_asyncDataSourceFlags = {};
memset(&_asyncDataSourceFlags, 0, sizeof(_asyncDataSourceFlags));
} else { } else {
_asyncDataSource = asyncDataSource; _asyncDataSource = asyncDataSource;
_proxyDataSource = [[ASCollectionViewProxy alloc] initWithTarget:_asyncDataSource interceptor:self]; _proxyDataSource = [[ASCollectionViewProxy alloc] initWithTarget:_asyncDataSource interceptor:self];
@@ -482,7 +419,8 @@ static NSString * const kReuseIdentifier = @"_ASCollectionReuseIdentifier";
_asyncDataSourceFlags.collectionNodeNumberOfItemsInSection = [_asyncDataSource respondsToSelector:@selector(collectionNode:numberOfItemsInSection:)]; _asyncDataSourceFlags.collectionNodeNumberOfItemsInSection = [_asyncDataSource respondsToSelector:@selector(collectionNode:numberOfItemsInSection:)];
_asyncDataSourceFlags.collectionNodeContextForSection = [_asyncDataSource respondsToSelector:@selector(collectionNode:contextForSection:)]; _asyncDataSourceFlags.collectionNodeContextForSection = [_asyncDataSource respondsToSelector:@selector(collectionNode:contextForSection:)];
_asyncDataSourceFlags.collectionNodeNodeForSupplementaryElement = [_asyncDataSource respondsToSelector:@selector(collectionNode:nodeForSupplementaryElementOfKind:atIndexPath:)]; _asyncDataSourceFlags.collectionNodeNodeForSupplementaryElement = [_asyncDataSource respondsToSelector:@selector(collectionNode:nodeForSupplementaryElementOfKind:atIndexPath:)];
_asyncDataSourceFlags.collectionNodeSupplementaryElementKindsInSection = [_asyncDataSource respondsToSelector:@selector(collectionNode:supplementaryElementKindsInSection:)];
_asyncDataSourceFlags.interop = [_asyncDataSource conformsToProtocol:@protocol(ASCollectionDataSourceInterop)];
ASDisplayNodeAssert(_asyncDataSourceFlags.collectionNodeNumberOfItemsInSection || _asyncDataSourceFlags.collectionViewNumberOfItemsInSection, @"Data source must implement collectionNode:numberOfItemsInSection:"); ASDisplayNodeAssert(_asyncDataSourceFlags.collectionNodeNumberOfItemsInSection || _asyncDataSourceFlags.collectionViewNumberOfItemsInSection, @"Data source must implement collectionNode:numberOfItemsInSection:");
ASDisplayNodeAssert(_asyncDataSourceFlags.collectionNodeNodeBlockForItem ASDisplayNodeAssert(_asyncDataSourceFlags.collectionNodeNodeBlockForItem
@@ -520,8 +458,7 @@ static NSString * const kReuseIdentifier = @"_ASCollectionReuseIdentifier";
if (asyncDelegate == nil) { if (asyncDelegate == nil) {
_asyncDelegate = nil; _asyncDelegate = nil;
_proxyDelegate = _isDeallocating ? nil : [[ASCollectionViewProxy alloc] initWithTarget:nil interceptor:self]; _proxyDelegate = _isDeallocating ? nil : [[ASCollectionViewProxy alloc] initWithTarget:nil interceptor:self];
_asyncDataSourceFlags = {};
memset(&_asyncDelegateFlags, 0, sizeof(_asyncDelegateFlags));
} else { } else {
_asyncDelegate = asyncDelegate; _asyncDelegate = asyncDelegate;
_proxyDelegate = [[ASCollectionViewProxy alloc] initWithTarget:_asyncDelegate interceptor:self]; _proxyDelegate = [[ASCollectionViewProxy alloc] initWithTarget:_asyncDelegate interceptor:self];
@@ -561,6 +498,7 @@ static NSString * const kReuseIdentifier = @"_ASCollectionReuseIdentifier";
_asyncDelegateFlags.collectionNodeShouldShowMenuForItem = [_asyncDelegate respondsToSelector:@selector(collectionNode:shouldShowMenuForItemAtIndexPath:)]; _asyncDelegateFlags.collectionNodeShouldShowMenuForItem = [_asyncDelegate respondsToSelector:@selector(collectionNode:shouldShowMenuForItemAtIndexPath:)];
_asyncDelegateFlags.collectionNodeCanPerformActionForItem = [_asyncDelegate respondsToSelector:@selector(collectionNode:canPerformAction:forItemAtIndexPath:sender:)]; _asyncDelegateFlags.collectionNodeCanPerformActionForItem = [_asyncDelegate respondsToSelector:@selector(collectionNode:canPerformAction:forItemAtIndexPath:sender:)];
_asyncDelegateFlags.collectionNodePerformActionForItem = [_asyncDelegate respondsToSelector:@selector(collectionNode:performAction:forItemAtIndexPath:sender:)]; _asyncDelegateFlags.collectionNodePerformActionForItem = [_asyncDelegate respondsToSelector:@selector(collectionNode:performAction:forItemAtIndexPath:sender:)];
_asyncDelegateFlags.interop = [_asyncDelegate conformsToProtocol:@protocol(ASCollectionDelegateInterop)];
} }
super.delegate = (id<UICollectionViewDelegate>)_proxyDelegate; super.delegate = (id<UICollectionViewDelegate>)_proxyDelegate;
@@ -939,7 +877,13 @@ static NSString * const kReuseIdentifier = @"_ASCollectionReuseIdentifier";
- (UICollectionReusableView *)collectionView:(UICollectionView *)collectionView viewForSupplementaryElementOfKind:(NSString *)kind atIndexPath:(NSIndexPath *)indexPath - (UICollectionReusableView *)collectionView:(UICollectionView *)collectionView viewForSupplementaryElementOfKind:(NSString *)kind atIndexPath:(NSIndexPath *)indexPath
{ {
UICollectionReusableView *view = [self dequeueReusableSupplementaryViewOfKind:kind withReuseIdentifier:kReuseIdentifier forIndexPath:indexPath]; UICollectionReusableView *view;
if (_asyncDataSource && _asyncDataSourceFlags.interop) {
view = [(id<ASCollectionDataSourceInterop>)_asyncDataSource collectionView:collectionView viewForSupplementaryElementOfKind:kind atIndexPath:indexPath];
} else {
view = [self dequeueReusableSupplementaryViewOfKind:kind withReuseIdentifier:kReuseIdentifier forIndexPath:indexPath];
}
ASCellNode *node = [_dataController supplementaryNodeOfKind:kind atIndexPath:indexPath]; ASCellNode *node = [_dataController supplementaryNodeOfKind:kind atIndexPath:indexPath];
ASDisplayNodeAssert(node != nil, @"Supplementary node should exist. Kind = %@, indexPath = %@, collectionDataSource = %@", kind, indexPath, self); ASDisplayNodeAssert(node != nil, @"Supplementary node should exist. Kind = %@, indexPath = %@, collectionDataSource = %@", kind, indexPath, self);
[_rangeController configureContentView:view forCellNode:node]; [_rangeController configureContentView:view forCellNode:node];
@@ -948,7 +892,12 @@ static NSString * const kReuseIdentifier = @"_ASCollectionReuseIdentifier";
- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath - (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath
{ {
_ASCollectionViewCell *cell = [self dequeueReusableCellWithReuseIdentifier:kReuseIdentifier forIndexPath:indexPath]; _ASCollectionViewCell *cell;
if (_asyncDataSource && _asyncDataSourceFlags.interop) {
cell = [(id<ASCollectionDataSourceInterop>)_asyncDataSource collectionView:collectionView cellForItemAtIndexPath:indexPath];
} else {
cell = [self dequeueReusableCellWithReuseIdentifier:kReuseIdentifier forIndexPath:indexPath];
}
ASCellNode *node = [self nodeForItemAtIndexPath:indexPath]; ASCellNode *node = [self nodeForItemAtIndexPath:indexPath];
cell.node = node; cell.node = node;
@@ -979,7 +928,9 @@ static NSString * const kReuseIdentifier = @"_ASCollectionReuseIdentifier";
ASDisplayNodeAssertNotNil(cellNode, @"Expected node associated with cell that will be displayed not to be nil. indexPath: %@", indexPath); ASDisplayNodeAssertNotNil(cellNode, @"Expected node associated with cell that will be displayed not to be nil. indexPath: %@", indexPath);
if (_asyncDelegateFlags.collectionNodeWillDisplayItem) { if (_asyncDelegateFlags.interop) {
[(id<ASCollectionDelegateInterop>)_asyncDelegate collectionView:collectionView willDisplayCell:cell forItemAtIndexPath:indexPath];
} else if (_asyncDelegateFlags.collectionNodeWillDisplayItem) {
if (ASCollectionNode *collectionNode = self.collectionNode) { if (ASCollectionNode *collectionNode = self.collectionNode) {
[_asyncDelegate collectionNode:collectionNode willDisplayItemWithNode:cellNode]; [_asyncDelegate collectionNode:collectionNode willDisplayItemWithNode:cellNode];
} }
@@ -1004,7 +955,9 @@ static NSString * const kReuseIdentifier = @"_ASCollectionReuseIdentifier";
ASCellNode *cellNode = [cell node]; ASCellNode *cellNode = [cell node];
ASDisplayNodeAssertNotNil(cellNode, @"Expected node associated with removed cell not to be nil."); ASDisplayNodeAssertNotNil(cellNode, @"Expected node associated with removed cell not to be nil.");
if (_asyncDelegateFlags.collectionNodeDidEndDisplayingItem) { if (_asyncDelegateFlags.interop) {
[(id<ASCollectionDelegateInterop>)_asyncDelegate collectionView:collectionView didEndDisplayingCell:cell forItemAtIndexPath:indexPath];
} else if (_asyncDelegateFlags.collectionNodeDidEndDisplayingItem) {
if (ASCollectionNode *collectionNode = self.collectionNode) { if (ASCollectionNode *collectionNode = self.collectionNode) {
[_asyncDelegate collectionNode:collectionNode didEndDisplayingItemWithNode:cellNode]; [_asyncDelegate collectionNode:collectionNode didEndDisplayingItemWithNode:cellNode];
} }
@@ -1544,10 +1497,20 @@ static NSString * const kReuseIdentifier = @"_ASCollectionReuseIdentifier";
return node; return node;
} }
// TODO: Lock this - (NSArray *)supplementaryNodeKindsInDataController:(ASCollectionDataController *)dataController sections:(NSIndexSet *)sections
- (NSArray *)supplementaryNodeKindsInDataController:(ASCollectionDataController *)dataController
{ {
return [_registeredSupplementaryKinds allObjects]; if (_asyncDataSourceFlags.collectionNodeSupplementaryElementKindsInSection) {
NSMutableSet *kinds = [NSMutableSet set];
GET_COLLECTIONNODE_OR_RETURN(collectionNode, @[]);
[sections enumerateIndexesUsingBlock:^(NSUInteger section, BOOL * _Nonnull stop) {
NSArray *kindsForSection = [_asyncDataSource collectionNode:collectionNode supplementaryElementKindsInSection:section];
[kinds addObjectsFromArray:kindsForSection];
}];
return [kinds allObjects];
} else {
// TODO: Lock this
return [_registeredSupplementaryKinds allObjects];
}
} }
- (ASSizeRange)dataController:(ASCollectionDataController *)dataController constrainedSizeForSupplementaryNodeOfKind:(NSString *)kind atIndexPath:(NSIndexPath *)indexPath - (ASSizeRange)dataController:(ASCollectionDataController *)dataController constrainedSizeForSupplementaryNodeOfKind:(NSString *)kind atIndexPath:(NSIndexPath *)indexPath

View File

@@ -23,7 +23,7 @@ NS_ASSUME_NONNULL_BEGIN
- (NSInteger)numberOfSectionsInCollectionView:(UICollectionView *)collectionView ASDISPLAYNODE_DEPRECATED_MSG("Implement -numberOfSectionsInCollectionNode: instead."); - (NSInteger)numberOfSectionsInCollectionView:(UICollectionView *)collectionView ASDISPLAYNODE_DEPRECATED_MSG("Implement -numberOfSectionsInCollectionNode: instead.");
- (UICollectionReusableView *)collectionView:(UICollectionView *)collectionView viewForSupplementaryElementOfKind:(NSString *)kind atIndexPath:(NSIndexPath *)indexPath ASDISPLAYNODE_DEPRECATED_MSG("Implement - collectionNode:viewForSupplementaryElementOfKind:atIndexPath: instead."); - (UICollectionReusableView *)collectionView:(UICollectionView *)collectionView viewForSupplementaryElementOfKind:(NSString *)kind atIndexPath:(NSIndexPath *)indexPath ASDISPLAYNODE_DEPRECATED_MSG("Implement - collectionNode:nodeForSupplementaryElementOfKind:atIndexPath: instead.");
@end @end

View File

@@ -389,11 +389,10 @@ static ASDisplayNodeMethodOverrides GetASDisplayNodeMethodOverrides(Class c)
{ {
ASDN::MutexLocker l(__instanceLock__); ASDN::MutexLocker l(__instanceLock__);
if ([self _isNodeLoaded]) { if ([self _isNodeLoaded]) {
ASDisplayNodeFailAssert(@"Attempt to call %@ on node after it was loaded. Node: %@", NSStringFromSelector(_cmd), self); ASDisplayNodeAssertThreadAffinity(self);
return; ASDN::MutexUnlocker l(__instanceLock__);
} body(self);
} else if (_onDidLoadBlocks == nil) {
if (_onDidLoadBlocks == nil) {
_onDidLoadBlocks = [NSMutableArray arrayWithObject:body]; _onDidLoadBlocks = [NSMutableArray arrayWithObject:body];
} else { } else {
[_onDidLoadBlocks addObject:body]; [_onDidLoadBlocks addObject:body];
@@ -663,11 +662,11 @@ static ASDisplayNodeMethodOverrides GetASDisplayNodeMethodOverrides(Class c)
ASDN::MutexLocker l(__instanceLock__); ASDN::MutexLocker l(__instanceLock__);
ASDisplayNodeLogEvent(self, @"didLoad"); ASDisplayNodeLogEvent(self, @"didLoad");
[self didLoad];
for (ASDisplayNodeDidLoadBlock block in _onDidLoadBlocks) { for (ASDisplayNodeDidLoadBlock block in _onDidLoadBlocks) {
block(self); block(self);
} }
_onDidLoadBlocks = nil; _onDidLoadBlocks = nil;
[self didLoad];
} }
- (void)didLoad - (void)didLoad

View File

@@ -0,0 +1,66 @@
//
// ASIGListKitMethodImplementations.h
// AsyncDisplayKit
//
// Created by Adlai Holler on 1/19/17.
// Copyright © 2017 Facebook. All rights reserved.
//
/**
* If you are using AsyncDisplayKit with IGListKit, you should use
* these macros to provide implementations of methods like
* -cellForItemAtIndex: that don't apply when used with AsyncDisplayKit.
*
* Your section controllers should also conform to @c ASSectionController and your
* supplementary view sources should conform to @c ASSupplementaryNodeSource.
*/
#if IG_LIST_KIT
#import <AsyncDisplayKit/_ASCollectionViewCell.h>
/**
* The implementation of viewForSupplementaryElementOfKind that connects
* IGSupplementaryViewSource to AsyncDisplayKit. Add this into the .m file
* for your `ASIGListSupplementaryViewSource` and implement the ASDK-specific
* method `nodeForSupplementaryElementOfKind:` to provide your node.
*
* @param sectionController The section controller this supplementary source is
* working on behalf of. For example, `self` or `self.sectionController`.
*/
#define ASIGSupplementarySourceViewForSupplementaryElementImplementation(sectionController) \
- (__kindof UICollectionReusableView *)viewForSupplementaryElementOfKind:(NSString *)elementKind atIndex:(NSInteger)index { \
return [self.collectionContext dequeueReusableSupplementaryViewOfKind:elementKind forSectionController:sectionController class:[UICollectionReusableView class] atIndex:index]; \
}
/**
* The implementation of sizeForSupplementaryViewOfKind that connects
* IGSupplementaryViewSource to AsyncDisplayKit. Add this into the .m file
* for your `ASIGListSupplementaryViewSource` and implement the ASDK-specific
* method `nodeForSupplementaryElementOfKind:` to provide your node which should
* size itself. You can set `node.style.preferredSize` if you want to fix the size.
*
* @param sectionController The section controller this supplementary source is
* working on behalf of. For example, `self` or `self.sectionController`.
*/
#define ASIGSupplementarySourceSizeForSupplementaryElementImplementation \
- (CGSize)sizeForSupplementaryViewOfKind:(NSString *)elementKind atIndex:(NSInteger)index {\
ASDisplayNodeFailAssert(@"Did not expect %@ to be called.", NSStringFromSelector(_cmd)); \
return CGSizeZero; \
}
#define ASIGSectionControllerCellForIndexImplementation \
- (__kindof UICollectionViewCell *)cellForItemAtIndex:(NSInteger)index\
{\
return [self.collectionContext dequeueReusableCellOfClass:[_ASCollectionViewCell class] forSectionController:self atIndex:index]; \
}\
#define ASIGSectionControllerSizeForItemImplementation \
- (CGSize)sizeForItemAtIndex:(NSInteger)index \
{\
ASDisplayNodeFailAssert(@"Did not expect %@ to be called.", NSStringFromSelector(_cmd)); \
return CGSizeZero;\
}
#endif // IG_LIST_KIT

View File

@@ -0,0 +1,69 @@
//
// ASSectionController.h
// AsyncDisplayKit
//
// Created by Adlai Holler on 1/19/17.
// Copyright © 2017 Facebook. All rights reserved.
//
#import <Foundation/Foundation.h>
NS_ASSUME_NONNULL_BEGIN
/**
* A protocol that your section controllers should conform to,
* in addition to IGListSectionType, in order to be used with AsyncDisplayKit.
*
* @note Your supplementary view source should conform to @c ASSupplementaryNodeSource.
*/
@protocol ASSectionController <NSObject>
/**
* A method to provide the node block for the item at the given index.
* The node block you return will be run asynchronously off the main thread,
* so it's important to retrieve any objects from your section _outside_ the block
* because by the time the block is run, the array may have changed.
*
* @param index The index of the item.
* @return A block to be run concurrently to build the node for this item.
* @see collectionNode:nodeBlockForItemAtIndexPath:
*/
- (ASCellNodeBlock)nodeBlockForItemAtIndex:(NSInteger)index;
@optional
/**
* Asks the section controller whether it should batch fetch because the user is
* near the end of the current data set.
*
* @discussion Use this method to conditionally fetch batches. Example use cases are: limiting the total number of
* objects that can be fetched or no network connection.
*
* If not implemented, the assumed return value is @c YES.
*/
- (BOOL)shouldBatchFetch;
/**
* Asks the section controller to begin fetching more content (tail loading) because
* the user is near the end of the current data set.
*
* @param context A context object that must be notified when the batch fetch is completed.
*
* @discussion You must eventually call -completeBatchFetching: with an argument of YES in order to receive future
* notifications to do batch fetches. This method is called on a background queue.
*/
- (void)beginBatchFetchWithContext:(ASBatchContext *)context;
/**
* A method to provide the size range used for measuring the item
* at the given index.
*
* @param index The index of the item.
* @return A size range used for asynchronously measuring the node at this index.
* @see collectionNode:constrainedSizeForItemAtIndexPath:
*/
- (ASSizeRange)sizeRangeForItemAtIndex:(NSInteger)index;
@end
NS_ASSUME_NONNULL_END

View File

@@ -0,0 +1,40 @@
//
// ASSupplementaryNodeSource.h
// AsyncDisplayKit
//
// Created by Adlai Holler on 1/19/17.
// Copyright © 2017 Facebook. All rights reserved.
//
#import <Foundation/Foundation.h>
NS_ASSUME_NONNULL_BEGIN
@protocol ASSupplementaryNodeSource <NSObject>
/**
* A method to provide the node for the item at the given index.
*
* @param elementKind The kind of supplementary element.
* @param index The index of the item.
* @return A node for the supplementary element.
* @see collectionNode:nodeForSupplementaryElementOfKind:atIndexPath:
*/
- (ASCellNode *)nodeForSupplementaryElementOfKind:(NSString *)elementKind atIndex:(NSInteger)index;
@optional
/**
* A method to provide the size range used for measuring the supplementary
* element of the given kind at the given index.
*
* @param elementKind The kind of supplementary element.
* @param index The index of the item.
* @return A size range used for asynchronously measuring the node.
* @see collectionNode:constrainedSizeForSupplementaryElementOfKind:atIndexPath:
*/
- (ASSizeRange)sizeRangeForSupplementaryElementOfKind:(NSString *)elementKind atIndex:(NSInteger)index;
@end
NS_ASSUME_NONNULL_END

View File

@@ -17,3 +17,7 @@
// a user does not include the framework in the link binary with build step). // a user does not include the framework in the link binary with build step).
#define PIN_REMOTE_IMAGE __has_include(<PINRemoteImage/PINRemoteImage.h>) #define PIN_REMOTE_IMAGE __has_include(<PINRemoteImage/PINRemoteImage.h>)
#endif #endif
#ifndef IG_LIST_KIT
#define IG_LIST_KIT __has_include(<IGListKit/IGListKit.h>)
#endif

View File

@@ -34,6 +34,13 @@
#import <AsyncDisplayKit/ASCellNode.h> #import <AsyncDisplayKit/ASCellNode.h>
#import <AsyncDisplayKit/ASSectionContext.h> #import <AsyncDisplayKit/ASSectionContext.h>
#import <AsyncDisplayKit/ASSectionController.h>
#import <AsyncDisplayKit/ASSupplementaryNodeSource.h>
#if IG_LIST_KIT
#import <AsyncDisplayKit/IGListAdapter+AsyncDisplayKit.h>
#import <AsyncDisplayKit/ASIGListKitMethodImplementations.h>
#endif
#import <AsyncDisplayKit/ASScrollNode.h> #import <AsyncDisplayKit/ASScrollNode.h>
#import <AsyncDisplayKit/ASPagerFlowLayout.h> #import <AsyncDisplayKit/ASPagerFlowLayout.h>

View File

@@ -27,7 +27,7 @@ NS_ASSUME_NONNULL_BEGIN
*/ */
- (ASSizeRange)dataController:(ASCollectionDataController *)dataController constrainedSizeForSupplementaryNodeOfKind:(NSString *)kind atIndexPath:(NSIndexPath *)indexPath; - (ASSizeRange)dataController:(ASCollectionDataController *)dataController constrainedSizeForSupplementaryNodeOfKind:(NSString *)kind atIndexPath:(NSIndexPath *)indexPath;
- (NSArray *)supplementaryNodeKindsInDataController:(ASCollectionDataController *)dataController; - (NSArray *)supplementaryNodeKindsInDataController:(ASCollectionDataController *)dataController sections:(NSIndexSet *)sections;
- (NSUInteger)dataController:(ASCollectionDataController *)dataController supplementaryNodesOfKind:(NSString *)kind inSection:(NSUInteger)section; - (NSUInteger)dataController:(ASCollectionDataController *)dataController supplementaryNodesOfKind:(NSString *)kind inSection:(NSUInteger)section;

View File

@@ -17,6 +17,7 @@
#import "ASIndexedNodeContext.h" #import "ASIndexedNodeContext.h"
#import "ASSection.h" #import "ASSection.h"
#import "ASSectionContext.h" #import "ASSectionContext.h"
#import "NSIndexSet+ASHelpers.h"
//#define LOG(...) NSLog(__VA_ARGS__) //#define LOG(...) NSLog(__VA_ARGS__)
#define LOG(...) #define LOG(...)
@@ -26,6 +27,13 @@
NSInteger _nextSectionID; NSInteger _nextSectionID;
NSMutableArray<ASSection *> *_sections; NSMutableArray<ASSection *> *_sections;
NSArray<ASSection *> *_pendingSections; NSArray<ASSection *> *_pendingSections;
/**
* supplementaryKinds can only be accessed on the main thread
* and so we set this in the -prepare stage, and then read it during the -will
* stage of each update operation.
*/
NSArray *_supplementaryKindsForPendingOperation;
} }
- (id<ASCollectionDataControllerSource>)collectionDataSource; - (id<ASCollectionDataControllerSource>)collectionDataSource;
@@ -59,7 +67,7 @@
[_sections removeAllObjects]; [_sections removeAllObjects];
[self _populatePendingSectionsFromDataSource:sections]; [self _populatePendingSectionsFromDataSource:sections];
for (NSString *kind in [self supplementaryKinds]) { for (NSString *kind in [self supplementaryKindsInSections:sections]) {
LOG(@"Populating elements of kind: %@", kind); LOG(@"Populating elements of kind: %@", kind);
NSMutableArray<ASIndexedNodeContext *> *contexts = [NSMutableArray array]; NSMutableArray<ASIndexedNodeContext *> *contexts = [NSMutableArray array];
[self _populateSupplementaryNodesOfKind:kind withSections:sections mutableContexts:contexts]; [self _populateSupplementaryNodesOfKind:kind withSections:sections mutableContexts:contexts];
@@ -101,7 +109,7 @@
ASDisplayNodeAssertMainThread(); ASDisplayNodeAssertMainThread();
[self _populatePendingSectionsFromDataSource:sections]; [self _populatePendingSectionsFromDataSource:sections];
for (NSString *kind in [self supplementaryKinds]) { for (NSString *kind in [self supplementaryKindsInSections:sections]) {
LOG(@"Populating elements of kind: %@, for sections: %@", kind, sections); LOG(@"Populating elements of kind: %@, for sections: %@", kind, sections);
NSMutableArray<ASIndexedNodeContext *> *contexts = [NSMutableArray array]; NSMutableArray<ASIndexedNodeContext *> *contexts = [NSMutableArray array];
[self _populateSupplementaryNodesOfKind:kind withSections:sections mutableContexts:contexts]; [self _populateSupplementaryNodesOfKind:kind withSections:sections mutableContexts:contexts];
@@ -127,46 +135,29 @@
[_pendingNodeContexts removeAllObjects]; [_pendingNodeContexts removeAllObjects];
} }
- (void)prepareForDeleteSections:(NSIndexSet *)sections
{
_supplementaryKindsForPendingOperation = [self supplementaryKindsInSections:sections];
}
- (void)willDeleteSections:(NSIndexSet *)sections - (void)willDeleteSections:(NSIndexSet *)sections
{ {
[_sections removeObjectsAtIndexes:sections]; [_sections removeObjectsAtIndexes:sections];
for (NSString *kind in [self supplementaryKinds]) { for (NSString *kind in _supplementaryKindsForPendingOperation) {
NSArray *indexPaths = ASIndexPathsForMultidimensionalArrayAtIndexSet([self editingNodesOfKind:kind], sections); NSArray *indexPaths = ASIndexPathsForMultidimensionalArrayAtIndexSet([self editingNodesOfKind:kind], sections);
[self deleteNodesOfKind:kind atIndexPaths:indexPaths completion:nil]; [self deleteNodesOfKind:kind atIndexPaths:indexPaths completion:nil];
[self deleteSectionsOfKind:kind atIndexSet:sections completion:nil]; [self deleteSectionsOfKind:kind atIndexSet:sections completion:nil];
} }
} _supplementaryKindsForPendingOperation = nil;
- (void)willMoveSection:(NSInteger)section toSection:(NSInteger)newSection
{
ASSection *movedSection = [_sections objectAtIndex:section];
[_sections removeObjectAtIndex:section];
[_sections insertObject:movedSection atIndex:newSection];
NSIndexSet *sectionAsIndexSet = [NSIndexSet indexSetWithIndex:section];
for (NSString *kind in [self supplementaryKinds]) {
NSMutableArray *editingNodes = [self editingNodesOfKind:kind];
NSArray *indexPaths = ASIndexPathsForMultidimensionalArrayAtIndexSet(editingNodes, sectionAsIndexSet);
NSArray *nodes = ASFindElementsInMultidimensionalArrayAtIndexPaths(editingNodes, indexPaths);
[self deleteNodesOfKind:kind atIndexPaths:indexPaths completion:nil];
// update the section of indexpaths
NSMutableArray *updatedIndexPaths = [[NSMutableArray alloc] initWithCapacity:indexPaths.count];
for (NSIndexPath *indexPath in indexPaths) {
NSUInteger newItem = [indexPath indexAtPosition:indexPath.length - 1];
NSIndexPath *mappedIndexPath = [NSIndexPath indexPathForItem:newItem inSection:newSection];
[updatedIndexPaths addObject:mappedIndexPath];
}
[self insertNodes:nodes ofKind:kind atIndexPaths:indexPaths completion:nil];
}
} }
- (void)prepareForInsertRowsAtIndexPaths:(NSArray<NSIndexPath *> *)indexPaths - (void)prepareForInsertRowsAtIndexPaths:(NSArray<NSIndexPath *> *)indexPaths
{ {
ASDisplayNodeAssertMainThread(); ASDisplayNodeAssertMainThread();
for (NSString *kind in [self supplementaryKinds]) { NSIndexSet *sections = [NSIndexSet as_sectionsFromIndexPaths:indexPaths];
for (NSString *kind in [self supplementaryKindsInSections:sections]) {
LOG(@"Populating elements of kind: %@, for index paths: %@", kind, indexPaths); LOG(@"Populating elements of kind: %@, for index paths: %@", kind, indexPaths);
NSMutableArray<ASIndexedNodeContext *> *contexts = [NSMutableArray array]; NSMutableArray<ASIndexedNodeContext *> *contexts = [NSMutableArray array];
[self _populateSupplementaryNodesOfKind:kind atIndexPaths:indexPaths mutableContexts:contexts]; [self _populateSupplementaryNodesOfKind:kind atIndexPaths:indexPaths mutableContexts:contexts];
@@ -188,7 +179,9 @@
- (void)prepareForDeleteRowsAtIndexPaths:(NSArray<NSIndexPath *> *)indexPaths - (void)prepareForDeleteRowsAtIndexPaths:(NSArray<NSIndexPath *> *)indexPaths
{ {
ASDisplayNodeAssertMainThread(); ASDisplayNodeAssertMainThread();
for (NSString *kind in [self supplementaryKinds]) { NSIndexSet *sections = [NSIndexSet as_sectionsFromIndexPaths:indexPaths];
_supplementaryKindsForPendingOperation = [self supplementaryKindsInSections:sections];
for (NSString *kind in _supplementaryKindsForPendingOperation) {
NSMutableArray<ASIndexedNodeContext *> *contexts = [NSMutableArray array]; NSMutableArray<ASIndexedNodeContext *> *contexts = [NSMutableArray array];
[self _populateSupplementaryNodesOfKind:kind atIndexPaths:indexPaths mutableContexts:contexts]; [self _populateSupplementaryNodesOfKind:kind atIndexPaths:indexPaths mutableContexts:contexts];
_pendingNodeContexts[kind] = contexts; _pendingNodeContexts[kind] = contexts;
@@ -197,7 +190,7 @@
- (void)willDeleteRowsAtIndexPaths:(NSArray<NSIndexPath *> *)indexPaths - (void)willDeleteRowsAtIndexPaths:(NSArray<NSIndexPath *> *)indexPaths
{ {
for (NSString *kind in [self supplementaryKinds]) { for (NSString *kind in _supplementaryKindsForPendingOperation) {
NSArray<NSIndexPath *> *deletedIndexPaths = ASIndexPathsInMultidimensionalArrayIntersectingIndexPaths([self editingNodesOfKind:kind], indexPaths); NSArray<NSIndexPath *> *deletedIndexPaths = ASIndexPathsInMultidimensionalArrayIntersectingIndexPaths([self editingNodesOfKind:kind], indexPaths);
[self deleteNodesOfKind:kind atIndexPaths:deletedIndexPaths completion:nil]; [self deleteNodesOfKind:kind atIndexPaths:deletedIndexPaths completion:nil];
@@ -216,6 +209,7 @@
}]; }];
} }
[_pendingNodeContexts removeAllObjects]; [_pendingNodeContexts removeAllObjects];
_supplementaryKindsForPendingOperation = nil;
} }
- (void)_populatePendingSectionsFromDataSource:(NSIndexSet *)sectionIndexes - (void)_populatePendingSectionsFromDataSource:(NSIndexSet *)sectionIndexes
@@ -323,9 +317,9 @@
#pragma mark - Private Helpers #pragma mark - Private Helpers
- (NSArray *)supplementaryKinds - (NSArray *)supplementaryKindsInSections:(NSIndexSet *)sections
{ {
return [self.collectionDataSource supplementaryNodeKindsInDataController:self]; return [self.collectionDataSource supplementaryNodeKindsInDataController:self sections:sections];
} }
- (id<ASCollectionDataControllerSource>)collectionDataSource - (id<ASCollectionDataControllerSource>)collectionDataSource

View File

@@ -66,24 +66,32 @@
- (ASSizeRange)collectionView:(ASCollectionView *)collectionView constrainedSizeForNodeAtIndexPath:(NSIndexPath *)indexPath - (ASSizeRange)collectionView:(ASCollectionView *)collectionView constrainedSizeForNodeAtIndexPath:(NSIndexPath *)indexPath
{ {
ASSizeRange result = ASSizeRangeUnconstrained;
if (_delegateFlags.implementsConstrainedSizeForItemAtIndexPath) { if (_delegateFlags.implementsConstrainedSizeForItemAtIndexPath) {
return [collectionView.asyncDelegate collectionNode:collectionView.collectionNode constrainedSizeForItemAtIndexPath:indexPath]; result = [collectionView.asyncDelegate collectionNode:collectionView.collectionNode constrainedSizeForItemAtIndexPath:indexPath];
} else if (_delegateFlags.implementsConstrainedSizeForNodeAtIndexPathDeprecated) { } else if (_delegateFlags.implementsConstrainedSizeForNodeAtIndexPathDeprecated) {
#pragma clang diagnostic push #pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wdeprecated-declarations" #pragma clang diagnostic ignored "-Wdeprecated-declarations"
return [collectionView.asyncDelegate collectionView:collectionView constrainedSizeForNodeAtIndexPath:indexPath]; result = [collectionView.asyncDelegate collectionView:collectionView constrainedSizeForNodeAtIndexPath:indexPath];
#pragma clang diagnostic pop #pragma clang diagnostic pop
} else { } else {
// With 2.0 `collectionView:constrainedSizeForNodeAtIndexPath:` was moved to the delegate. Assert if not implemented on the delegate but on the data source // With 2.0 `collectionView:constrainedSizeForNodeAtIndexPath:` was moved to the delegate. Assert if not implemented on the delegate but on the data source
ASDisplayNodeAssert([collectionView.asyncDataSource respondsToSelector:@selector(collectionView:constrainedSizeForNodeAtIndexPath:)] == NO, @"collectionView:constrainedSizeForNodeAtIndexPath: was moved from the ASCollectionDataSource to the ASCollectionDelegate."); ASDisplayNodeAssert([collectionView.asyncDataSource respondsToSelector:@selector(collectionView:constrainedSizeForNodeAtIndexPath:)] == NO, @"collectionView:constrainedSizeForNodeAtIndexPath: was moved from the ASCollectionDataSource to the ASCollectionDelegate.");
} }
CGSize itemSize = _layout.itemSize; // If we got no size range:
if (CGSizeEqualToSize(itemSize, kDefaultItemSize) == NO) { if (ASSizeRangeEqualToSizeRange(result, ASSizeRangeUnconstrained)) {
return ASSizeRangeMake(itemSize, itemSize); // Use itemSize if they set it.
CGSize itemSize = _layout.itemSize;
if (CGSizeEqualToSize(itemSize, kDefaultItemSize) == NO) {
result = ASSizeRangeMake(itemSize, itemSize);
} else {
// Compute constraint from scroll direction otherwise.
result = NodeConstrainedSizeForScrollDirection(collectionView);
}
} }
return NodeConstrainedSizeForScrollDirection(collectionView); return result;
} }
- (ASSizeRange)collectionView:(ASCollectionView *)collectionView constrainedSizeForSupplementaryNodeOfKind:(NSString *)kind atIndexPath:(NSIndexPath *)indexPath - (ASSizeRange)collectionView:(ASCollectionView *)collectionView constrainedSizeForSupplementaryNodeOfKind:(NSString *)kind atIndexPath:(NSIndexPath *)indexPath

View File

@@ -10,6 +10,7 @@
#import "ASCollectionView.h" #import "ASCollectionView.h"
#import "ASCollectionView+Undeprecated.h" #import "ASCollectionView+Undeprecated.h"
#import "ASCollectionInternal.h"
#pragma mark - Helper Functions #pragma mark - Helper Functions

View File

@@ -719,6 +719,8 @@ NSString * const ASCollectionInvalidUpdateException = @"ASCollectionInvalidUpdat
[_nodeContexts[ASDataControllerRowNodeKind] removeObjectsAtIndexes:sections]; [_nodeContexts[ASDataControllerRowNodeKind] removeObjectsAtIndexes:sections];
dispatch_group_wait(_editingTransactionGroup, DISPATCH_TIME_FOREVER); dispatch_group_wait(_editingTransactionGroup, DISPATCH_TIME_FOREVER);
[self prepareForDeleteSections:sections];
dispatch_group_async(_editingTransactionGroup, _editingTransactionQueue, ^{ dispatch_group_async(_editingTransactionGroup, _editingTransactionQueue, ^{
[self willDeleteSections:sections]; [self willDeleteSections:sections];
@@ -745,6 +747,11 @@ NSString * const ASCollectionInvalidUpdateException = @"ASCollectionInvalidUpdat
// Optional template hook for subclasses (See ASDataController+Subclasses.h) // Optional template hook for subclasses (See ASDataController+Subclasses.h)
} }
- (void)prepareForDeleteSections:(NSIndexSet *)sections
{
// Optional template hook for subclasses (See ASDataController+Subclasses.h)
}
- (void)willInsertSections:(NSIndexSet *)sections - (void)willInsertSections:(NSIndexSet *)sections
{ {
// Optional template hook for subclasses (See ASDataController+Subclasses.h) // Optional template hook for subclasses (See ASDataController+Subclasses.h)

View File

@@ -22,4 +22,7 @@
- (NSString *)as_smallDescription; - (NSString *)as_smallDescription;
/// Returns all the section indexes contained in the index paths array.
+ (NSIndexSet *)as_sectionsFromIndexPaths:(NSArray<NSIndexPath *> *)indexPaths;
@end @end

View File

@@ -77,4 +77,13 @@
return result; return result;
} }
+ (NSIndexSet *)as_sectionsFromIndexPaths:(NSArray<NSIndexPath *> *)indexPaths
{
NSMutableIndexSet *result = [NSMutableIndexSet indexSet];
for (NSIndexPath *indexPath in indexPaths) {
[result addIndex:indexPath.section];
}
return result;
}
@end @end

View File

@@ -0,0 +1,17 @@
//
// _ASCollectionViewCell.h
// AsyncDisplayKit
//
// Created by Adlai Holler on 1/30/17.
// Copyright © 2017 Facebook. All rights reserved.
//
#import <UIKit/UIKit.h>
@class ASCellNode;
@interface _ASCollectionViewCell : UICollectionViewCell
@property (nonatomic, weak) ASCellNode *node;
@property (nonatomic, strong) UICollectionViewLayoutAttributes *layoutAttributes;
@end

View File

@@ -0,0 +1,74 @@
//
// _ASCollectionViewCell.m
// AsyncDisplayKit
//
// Created by Adlai Holler on 1/30/17.
// Copyright © 2017 Facebook. All rights reserved.
//
#import "_ASCollectionViewCell.h"
#import "ASCellNode+Internal.h"
#import <AsyncDisplayKit/AsyncDisplayKit.h>
@implementation _ASCollectionViewCell
- (void)setNode:(ASCellNode *)node
{
ASDisplayNodeAssertMainThread();
node.layoutAttributes = _layoutAttributes;
_node = node;
self.backgroundColor = node.backgroundColor;
self.clipsToBounds = node.clipsToBounds;
[node __setSelectedFromUIKit:self.selected];
[node __setHighlightedFromUIKit:self.highlighted];
}
- (void)setSelected:(BOOL)selected
{
[super setSelected:selected];
[_node __setSelectedFromUIKit:selected];
}
- (void)setHighlighted:(BOOL)highlighted
{
[super setHighlighted:highlighted];
[_node __setHighlightedFromUIKit:highlighted];
}
- (void)setLayoutAttributes:(UICollectionViewLayoutAttributes *)layoutAttributes
{
_layoutAttributes = layoutAttributes;
_node.layoutAttributes = layoutAttributes;
}
- (void)prepareForReuse
{
self.layoutAttributes = nil;
// Need to clear node pointer before UIKit calls setSelected:NO / setHighlighted:NO on its cells
self.node = nil;
[super prepareForReuse];
}
/**
* In the initial case, this is called by UICollectionView during cell dequeueing, before
* we get a chance to assign a node to it, so we must be sure to set these layout attributes
* on our node when one is next assigned to us in @c setNode: . Since there may be cases when we _do_ already
* have our node assigned e.g. during a layout update for existing cells, we also attempt
* to update it now.
*/
- (void)applyLayoutAttributes:(UICollectionViewLayoutAttributes *)layoutAttributes
{
self.layoutAttributes = layoutAttributes;
}
/**
* Keep our node filling our content view.
*/
- (void)layoutSubviews
{
[super layoutSubviews];
self.node.frame = self.contentView.bounds;
}
@end

View File

@@ -0,0 +1,34 @@
//
// IGListAdapter+AsyncDisplayKit.h
// AsyncDisplayKit
//
// Created by Adlai Holler on 1/19/17.
// Copyright © 2017 Facebook. All rights reserved.
//
#if IG_LIST_KIT
#import <IGListKit/IGListKit.h>
NS_ASSUME_NONNULL_BEGIN
@class ASCollectionNode;
@interface IGListAdapter (AsyncDisplayKit)
/**
* Connect this list adapter to the given collection node.
*
* @param collectionNode The collection node to drive with this list adapter.
*
* @note This method may only be called once per list adapter,
* and it must be called on the main thread. -[UIViewController init]
* is a good place to call it. This method does not retain the collection node.
*/
- (void)setASDKCollectionNode:(ASCollectionNode *)collectionNode;
@end
NS_ASSUME_NONNULL_END
#endif // IG_LIST_KIT

View File

@@ -0,0 +1,45 @@
//
// IGListAdapter+AsyncDisplayKit.m
// AsyncDisplayKit
//
// Created by Adlai Holler on 1/19/17.
// Copyright © 2017 Facebook. All rights reserved.
//
#if IG_LIST_KIT
#import "IGListAdapter+AsyncDisplayKit.h"
#import "ASIGListAdapterBasedDataSource.h"
#import "ASAssert.h"
#import <objc/runtime.h>
@implementation IGListAdapter (AsyncDisplayKit)
- (void)setASDKCollectionNode:(ASCollectionNode *)collectionNode
{
ASDisplayNodeAssertMainThread();
// Attempt to retrieve previous data source.
ASIGListAdapterBasedDataSource *dataSource = objc_getAssociatedObject(self, _cmd);
// Bomb if we already made one.
if (dataSource != nil) {
ASDisplayNodeFailAssert(@"Attempt to call %@ multiple times on the same list adapter. Not currently allowed!", NSStringFromSelector(_cmd));
return;
}
// Make a data source and retain it.
dataSource = [[ASIGListAdapterBasedDataSource alloc] initWithListAdapter:self];
objc_setAssociatedObject(self, _cmd, dataSource, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
// Attach the data source to the collection node.
collectionNode.dataSource = dataSource;
collectionNode.delegate = dataSource;
__weak IGListAdapter *weakSelf = self;
[collectionNode onDidLoad:^(__kindof ASCollectionNode * _Nonnull collectionNode) {
weakSelf.collectionView = collectionNode.view;
}];
}
@end
#endif // IG_LIST_KIT

View File

@@ -0,0 +1,34 @@
//
// ASCollectionDataSourceInterop.h
// AsyncDisplayKit
//
// Created by Adlai Holler on 1/20/17.
// Copyright © 2017 Facebook. All rights reserved.
//
#import <AsyncDisplayKit/AsyncDisplayKit.h>
NS_ASSUME_NONNULL_BEGIN
/**
* Protocols that allow the data source/delegate extra hooks,
* to facilitate interop e.g. with IGListKit.
*/
@protocol ASCollectionDataSourceInterop <ASCollectionDataSource>
- (__kindof UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath;
- (UICollectionReusableView *)collectionView:(UICollectionView *)collectionView viewForSupplementaryElementOfKind:(NSString *)kind atIndexPath:(NSIndexPath *)indexPath;
@end
@protocol ASCollectionDelegateInterop <ASCollectionDelegate>
- (void)collectionView:(UICollectionView *)collectionView willDisplayCell:(UICollectionViewCell *)cell forItemAtIndexPath:(NSIndexPath *)indexPath;
- (void)collectionView:(UICollectionView *)collectionView didEndDisplayingCell:(UICollectionViewCell *)cell forItemAtIndexPath:(NSIndexPath *)indexPath;
@end
NS_ASSUME_NONNULL_END

View File

@@ -113,6 +113,17 @@ typedef void (^ASDataControllerCompletionBlock)(NSArray<ASCellNode *> *nodes, NS
*/ */
- (void)willInsertSections:(NSIndexSet *)sections; - (void)willInsertSections:(NSIndexSet *)sections;
/**
* Notifies the subclass to perform setup before sections are deleted in the data controller
*
* @discussion This method will be performed before the data controller enters its editing queue.
* The data source is locked at this point and accessing it is safe. Use this method to set up any nodes or
* data stores before entering into editing the backing store on a background thread.
*
* @param sections Indices of sections to be inserted
*/
- (void)prepareForDeleteSections:(NSIndexSet *)sections;
/** /**
* Notifies the subclass that the data controller will delete sections at the given positions * Notifies the subclass that the data controller will delete sections at the given positions
* *
@@ -124,18 +135,6 @@ typedef void (^ASDataControllerCompletionBlock)(NSArray<ASCellNode *> *nodes, NS
*/ */
- (void)willDeleteSections:(NSIndexSet *)sections; - (void)willDeleteSections:(NSIndexSet *)sections;
/**
* Notifies the subclass that the data controller will move a section to a new position
*
* @discussion This method will be performed on the data controller's editing background queue before the parent's
* concrete implementation. This is a great place to perform any additional transformations like supplementary views
* or header/footer nodes.
*
* @param section Index of current section position
* @param newSection Index of new section position
*/
- (void)willMoveSection:(NSInteger)section toSection:(NSInteger)newSection;
/** /**
* Notifies the subclass to perform setup before rows are inserted in the data controller. * Notifies the subclass to perform setup before rows are inserted in the data controller.
* *

View File

@@ -0,0 +1,22 @@
//
// ASIGListAdapterBasedDataSource.h
// AsyncDisplayKit
//
// Created by Adlai Holler on 1/19/17.
// Copyright © 2017 Facebook. All rights reserved.
//
#if IG_LIST_KIT
#import <IGListKit/IGListKit.h>
#import <AsyncDisplayKit/AsyncDisplayKit.h>
#import "ASCollectionInteropProtocols.h"
AS_SUBCLASSING_RESTRICTED
@interface ASIGListAdapterBasedDataSource : NSObject <ASCollectionDataSourceInterop, ASCollectionDelegateInterop, ASCollectionDelegateFlowLayout>
- (instancetype)initWithListAdapter:(IGListAdapter *)listAdapter;
@end
#endif

View File

@@ -0,0 +1,315 @@
//
// ASIGListAdapterBasedDataSource.m
// AsyncDisplayKit
//
// Created by Adlai Holler on 1/19/17.
// Copyright © 2017 Facebook. All rights reserved.
//
#if IG_LIST_KIT
#import "ASIGListAdapterBasedDataSource.h"
#import <AsyncDisplayKit/AsyncDisplayKit.h>
#import <objc/runtime.h>
typedef IGListSectionController<IGListSectionType, ASSectionController> ASIGSectionController;
/// The optional methods that a class implements from ASSectionController.
/// Note: Bitfields are not supported by NSValue so we can't use them.
typedef struct {
BOOL sizeRangeForItem;
BOOL shouldBatchFetch;
BOOL beginBatchFetchWithContext;
} ASSectionControllerOverrides;
/// The optional methods that a class implements from ASSupplementaryNodeSource.
/// Note: Bitfields are not supported by NSValue so we can't use them.
typedef struct {
BOOL sizeRangeForSupplementary;
} ASSupplementarySourceOverrides;
@protocol ASIGSupplementaryNodeSource <IGListSupplementaryViewSource, ASSupplementaryNodeSource>
@end
@interface ASIGListAdapterBasedDataSource ()
@property (nonatomic, weak, readonly) IGListAdapter *listAdapter;
@property (nonatomic, readonly) id<UICollectionViewDelegateFlowLayout> delegate;
@property (nonatomic, readonly) id<UICollectionViewDataSource> dataSource;
/**
* The section controller that we will forward beginBatchFetchWithContext: to.
* Since shouldBatchFetch: is called on main, we capture the last section controller in there,
* and then we use it and clear it in beginBatchFetchWithContext: (on default queue).
*
* It is safe to use it without a lock in this limited way, since those two methods will
* never execute in parallel.6
*/
@property (nonatomic, weak) ASIGSectionController *sectionControllerForBatchFetching;
@end
@implementation ASIGListAdapterBasedDataSource
- (instancetype)initWithListAdapter:(IGListAdapter *)listAdapter
{
if (self = [super init]) {
[ASIGListAdapterBasedDataSource setASCollectionViewSuperclass];
[ASIGListAdapterBasedDataSource configureUpdater:listAdapter.updater];
ASDisplayNodeAssert([listAdapter conformsToProtocol:@protocol(UICollectionViewDataSource)], @"Expected IGListAdapter to conform to UICollectionViewDataSource.");
ASDisplayNodeAssert([listAdapter conformsToProtocol:@protocol(UICollectionViewDelegateFlowLayout)], @"Expected IGListAdapter to conform to UICollectionViewDelegateFlowLayout.");
_listAdapter = listAdapter;
}
return self;
}
- (id<UICollectionViewDataSource>)dataSource
{
return (id<UICollectionViewDataSource>)_listAdapter;
}
- (id<UICollectionViewDelegateFlowLayout>)delegate
{
return (id<UICollectionViewDelegateFlowLayout>)_listAdapter;
}
#pragma mark - ASCollectionDelegate
- (void)collectionNode:(ASCollectionNode *)collectionNode didSelectItemAtIndexPath:(NSIndexPath *)indexPath
{
[self.delegate collectionView:collectionNode.view didSelectItemAtIndexPath:indexPath];
}
- (void)scrollViewDidScroll:(UIScrollView *)scrollView
{
[self.delegate scrollViewDidScroll:scrollView];
}
- (void)scrollViewWillBeginDragging:(UIScrollView *)scrollView
{
[self.delegate scrollViewWillBeginDragging:scrollView];
}
- (void)scrollViewDidEndDragging:(UIScrollView *)scrollView willDecelerate:(BOOL)decelerate
{
[self.delegate scrollViewDidEndDragging:scrollView willDecelerate:decelerate];
}
- (BOOL)shouldBatchFetchForCollectionNode:(ASCollectionNode *)collectionNode
{
NSInteger sectionCount = [self numberOfSectionsInCollectionNode:collectionNode];
if (sectionCount == 0) {
return NO;
}
// If they implement shouldBatchFetch, call it. Otherwise, just say YES if they implement beginBatchFetch.
ASIGSectionController *ctrl = [self sectionControllerForSection:sectionCount - 1];
ASSectionControllerOverrides o = [ASIGListAdapterBasedDataSource overridesForSectionControllerClass:ctrl.class];
BOOL result = (o.shouldBatchFetch ? [ctrl shouldBatchFetch] : o.beginBatchFetchWithContext);
if (result) {
self.sectionControllerForBatchFetching = ctrl;
}
return result;
}
- (void)collectionNode:(ASCollectionNode *)collectionNode willBeginBatchFetchWithContext:(ASBatchContext *)context
{
ASIGSectionController *ctrl = self.sectionControllerForBatchFetching;
self.sectionControllerForBatchFetching = nil;
[ctrl beginBatchFetchWithContext:context];
}
/**
* Note: It is not documented that ASCollectionNode will forward these UIKit delegate calls if they are implemented.
* It is not considered harmful to do so, and adding them to documentation will confuse most users, who should
* instead using the ASCollectionDelegate callbacks.
*/
#pragma mark - ASCollectionDelegateInterop
- (void)collectionView:(UICollectionView *)collectionView willDisplayCell:(UICollectionViewCell *)cell forItemAtIndexPath:(NSIndexPath *)indexPath
{
[self.delegate collectionView:collectionView willDisplayCell:cell forItemAtIndexPath:indexPath];
}
- (void)collectionView:(UICollectionView *)collectionView didEndDisplayingCell:(UICollectionViewCell *)cell forItemAtIndexPath:(NSIndexPath *)indexPath
{
[self.delegate collectionView:collectionView didEndDisplayingCell:cell forItemAtIndexPath:indexPath];
}
#pragma mark - ASCollectionDelegateFlowLayout
- (ASSizeRange)collectionNode:(ASCollectionNode *)collectionNode sizeRangeForHeaderInSection:(NSInteger)section
{
id<ASIGSupplementaryNodeSource> src = [self supplementaryElementSourceForSection:section];
if ([ASIGListAdapterBasedDataSource overridesForSupplementarySourceClass:[src class]].sizeRangeForSupplementary) {
return [src sizeRangeForSupplementaryElementOfKind:UICollectionElementKindSectionHeader atIndex:0];
} else {
return ASSizeRangeZero;
}
}
- (ASSizeRange)collectionNode:(ASCollectionNode *)collectionNode sizeRangeForFooterInSection:(NSInteger)section
{
id<ASIGSupplementaryNodeSource> src = [self supplementaryElementSourceForSection:section];
if ([ASIGListAdapterBasedDataSource overridesForSupplementarySourceClass:[src class]].sizeRangeForSupplementary) {
return [src sizeRangeForSupplementaryElementOfKind:UICollectionElementKindSectionFooter atIndex:0];
} else {
return ASSizeRangeZero;
}
}
- (UIEdgeInsets)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout *)collectionViewLayout insetForSectionAtIndex:(NSInteger)section
{
return [self.delegate collectionView:collectionView layout:collectionViewLayout insetForSectionAtIndex:section];
}
- (CGFloat)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout *)collectionViewLayout minimumLineSpacingForSectionAtIndex:(NSInteger)section
{
return [self.delegate collectionView:collectionView layout:collectionViewLayout minimumLineSpacingForSectionAtIndex:section];
}
- (CGFloat)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout *)collectionViewLayout minimumInteritemSpacingForSectionAtIndex:(NSInteger)section
{
return [self.delegate collectionView:collectionView layout:collectionViewLayout minimumInteritemSpacingForSectionAtIndex:section];
}
#pragma mark - ASCollectionDataSource
- (NSInteger)collectionNode:(ASCollectionNode *)collectionNode numberOfItemsInSection:(NSInteger)section
{
return [self.dataSource collectionView:collectionNode.view numberOfItemsInSection:section];
}
- (NSInteger)numberOfSectionsInCollectionNode:(ASCollectionNode *)collectionNode
{
return [self.dataSource numberOfSectionsInCollectionView:collectionNode.view];
}
- (ASCellNodeBlock)collectionNode:(ASCollectionNode *)collectionNode nodeBlockForItemAtIndexPath:(NSIndexPath *)indexPath
{
return [[self sectionControllerForSection:indexPath.section] nodeBlockForItemAtIndex:indexPath.item];
}
- (ASSizeRange)collectionNode:(ASCollectionNode *)collectionNode constrainedSizeForItemAtIndexPath:(NSIndexPath *)indexPath
{
ASIGSectionController *ctrl = [self sectionControllerForSection:indexPath.section];
if ([ASIGListAdapterBasedDataSource overridesForSectionControllerClass:ctrl.class].sizeRangeForItem) {
return [ctrl sizeRangeForItemAtIndex:indexPath.item];
} else {
return ASSizeRangeUnconstrained;
}
}
- (ASCellNode *)collectionNode:(ASCollectionNode *)collectionNode nodeForSupplementaryElementOfKind:(NSString *)kind atIndexPath:(NSIndexPath *)indexPath
{
return [[self supplementaryElementSourceForSection:indexPath.section] nodeForSupplementaryElementOfKind:kind atIndex:indexPath.item];
}
- (NSArray<NSString *> *)collectionNode:(ASCollectionNode *)collectionNode supplementaryElementKindsInSection:(NSInteger)section
{
return [[self supplementaryElementSourceForSection:section] supportedElementKinds];
}
#pragma mark - ASCollectionDataSourceInterop
- (__kindof UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(nonnull NSIndexPath *)indexPath
{
return [self.dataSource collectionView:collectionView cellForItemAtIndexPath:indexPath];
}
- (UICollectionReusableView *)collectionView:(UICollectionView *)collectionView viewForSupplementaryElementOfKind:(NSString *)kind atIndexPath:(NSIndexPath *)indexPath
{
return [self.dataSource collectionView:collectionView viewForSupplementaryElementOfKind:kind atIndexPath:indexPath];
}
#pragma mark - Helpers
- (id<ASIGSupplementaryNodeSource>)supplementaryElementSourceForSection:(NSInteger)section
{
ASIGSectionController *ctrl = [self sectionControllerForSection:section];
id<ASIGSupplementaryNodeSource> src = (id<ASIGSupplementaryNodeSource>)ctrl.supplementaryViewSource;
ASDisplayNodeAssert(src == nil || [src conformsToProtocol:@protocol(ASSupplementaryNodeSource)], @"Supplementary view source should conform to %@", NSStringFromProtocol(@protocol(ASSupplementaryNodeSource)));
return src;
}
- (ASIGSectionController *)sectionControllerForSection:(NSInteger)section
{
id object = [_listAdapter objectAtSection:section];
ASIGSectionController *ctrl = (ASIGSectionController *)[_listAdapter sectionControllerForObject:object];
ASDisplayNodeAssert([ctrl conformsToProtocol:@protocol(ASSectionController)], @"Expected section controller to conform to %@. Controller: %@", NSStringFromProtocol(@protocol(ASSectionController)), ctrl);
return ctrl;
}
/**
* Set ASCollectionView's superclass to IGListCollectionView.
* Scary! If IGListKit removed the subclassing restriction, we could
* use #if in the @interface to choose the superclass based on
* whether we have IGListKit available.
*/
+ (void)setASCollectionViewSuperclass
{
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wdeprecated-declarations"
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
class_setSuperclass([ASCollectionView class], [IGListCollectionView class]);
});
#pragma clang diagnostic pop
}
/// Ensure updater won't call reloadData on us.
+ (void)configureUpdater:(id<IGListUpdatingDelegate>)updater
{
// Cast to NSObject will be removed after https://github.com/Instagram/IGListKit/pull/435
if ([(id<NSObject>)updater isKindOfClass:[IGListAdapterUpdater class]]) {
[(IGListAdapterUpdater *)updater setAllowsBackgroundReloading:NO];
} else {
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
NSLog(@"WARNING: Use of non-%@ updater with AsyncDisplayKit is discouraged. Updater: %@", NSStringFromClass([IGListAdapterUpdater class]), updater);
});
}
}
+ (ASSupplementarySourceOverrides)overridesForSupplementarySourceClass:(Class)c
{
static NSCache<Class, NSValue *> *cache;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
cache = [[NSCache alloc] init];
});
NSValue *obj = [cache objectForKey:c];
ASSupplementarySourceOverrides o;
if (obj == nil) {
o.sizeRangeForSupplementary = [c instancesRespondToSelector:@selector(sizeRangeForSupplementaryElementOfKind:atIndex:)];
obj = [NSValue valueWithBytes:&o objCType:@encode(ASSupplementarySourceOverrides)];
[cache setObject:obj forKey:c];
} else {
[obj getValue:&o];
}
return o;
}
+ (ASSectionControllerOverrides)overridesForSectionControllerClass:(Class)c
{
static NSCache<Class, NSValue *> *cache;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
cache = [[NSCache alloc] init];
});
NSValue *obj = [cache objectForKey:c];
ASSectionControllerOverrides o;
if (obj == nil) {
o.sizeRangeForItem = [c instancesRespondToSelector:@selector(sizeRangeForItemAtIndex:)];
o.beginBatchFetchWithContext = [c instancesRespondToSelector:@selector(beginBatchFetchWithContext:)];
o.shouldBatchFetch = [c instancesRespondToSelector:@selector(shouldBatchFetch)];
obj = [NSValue valueWithBytes:&o objCType:@encode(ASSectionControllerOverrides)];
[cache setObject:obj forKey:c];
} else {
[obj getValue:&o];
}
return o;
}
@end
#endif // IG_LIST_KIT

View File

@@ -164,7 +164,7 @@
@interface ASCollectionView (InternalTesting) @interface ASCollectionView (InternalTesting)
- (NSArray *)supplementaryNodeKindsInDataController:(ASCollectionDataController *)dataController; - (NSArray *)supplementaryNodeKindsInDataController:(ASCollectionDataController *)dataController sections:(nonnull NSIndexSet *)sections;
@end @end
@@ -219,7 +219,7 @@
UICollectionViewFlowLayout *layout = [[UICollectionViewFlowLayout alloc] init]; UICollectionViewFlowLayout *layout = [[UICollectionViewFlowLayout alloc] init];
ASCollectionView *collectionView = [[ASCollectionView alloc] initWithFrame:CGRectZero collectionViewLayout:layout]; ASCollectionView *collectionView = [[ASCollectionView alloc] initWithFrame:CGRectZero collectionViewLayout:layout];
[collectionView registerSupplementaryNodeOfKind:UICollectionElementKindSectionHeader]; [collectionView registerSupplementaryNodeOfKind:UICollectionElementKindSectionHeader];
XCTAssertEqualObjects([collectionView supplementaryNodeKindsInDataController:nil], @[UICollectionElementKindSectionHeader]); XCTAssertEqualObjects([collectionView supplementaryNodeKindsInDataController:nil sections:[NSIndexSet indexSetWithIndex:0]], @[UICollectionElementKindSectionHeader]);
} }
- (void)testReloadIfNeeded - (void)testReloadIfNeeded

View File

@@ -2144,11 +2144,16 @@ static bool stringContainsPointer(NSString *description, id p) {
XCTAssertNoThrow([node.view layoutIfNeeded]); XCTAssertNoThrow([node.view layoutIfNeeded]);
} }
- (void)testThatOnDidLoadThrowsIfCalledOnLoaded - (void)testThatOnDidLoadThrowsIfCalledOnLoadedOffMain
{ {
ASTestDisplayNode *node = [[ASTestDisplayNode alloc] init]; ASTestDisplayNode *node = [[ASTestDisplayNode alloc] init];
[node view]; [node view];
XCTAssertThrows([node onDidLoad:^(ASDisplayNode * _Nonnull node) { }]); dispatch_semaphore_t sem = dispatch_semaphore_create(0);
[NSThread detachNewThreadWithBlock:^{
XCTAssertThrows([node onDidLoad:^(ASDisplayNode * _Nonnull node) { }]);
dispatch_semaphore_signal(sem);
}];
dispatch_semaphore_wait(sem, DISPATCH_TIME_FOREVER);
} }
- (void)testThatOnDidLoadWorks - (void)testThatOnDidLoadWorks

View File

@@ -30,7 +30,20 @@ if [ "$MODE" = "tests" ]; then
-scheme AsyncDisplayKit \ -scheme AsyncDisplayKit \
-sdk "$SDK" \ -sdk "$SDK" \
-destination "$PLATFORM" \ -destination "$PLATFORM" \
build test | xcpretty $FORMATTER build-for-testing test | xcpretty $FORMATTER
trap - EXIT
exit 0
fi
if [ "$MODE" = "tests_listkit" ]; then
echo "Building & testing AsyncDisplayKit+IGListKit."
pod install --project-directory=ASDKListKit
set -o pipefail && xcodebuild \
-workspace ASDKListKit/ASDKListKit.xcworkspace \
-scheme ASDKListKitTests \
-sdk "$SDK" \
-destination "$PLATFORM" \
build-for-testing test | xcpretty $FORMATTER
trap - EXIT trap - EXIT
exit 0 exit 0
fi fi

View File

@@ -21,7 +21,7 @@
#import "SupplementaryNode.h" #import "SupplementaryNode.h"
#import "ItemNode.h" #import "ItemNode.h"
@interface ViewController () <ASCollectionDataSource, ASCollectionViewDelegateFlowLayout> @interface ViewController () <ASCollectionDataSource, ASCollectionDelegateFlowLayout>
@property (nonatomic, strong) ASCollectionNode *collectionNode; @property (nonatomic, strong) ASCollectionNode *collectionNode;
@property (nonatomic, strong) NSArray *data; @property (nonatomic, strong) NSArray *data;

View File

@@ -1,6 +1,7 @@
source 'https://github.com/CocoaPods/Specs.git' source 'https://github.com/CocoaPods/Specs.git'
platform :ios, '7.0' platform :ios, '8.0'
target 'Sample' do target 'Sample' do
pod 'AsyncDisplayKit', :path => '../..' pod 'AsyncDisplayKit/IGListKit', :path => '../..'
pod 'AsyncDisplayKit/PINRemoteImage', :path => '../..'
end end

View File

@@ -31,6 +31,11 @@
768843931CAA37EF00D8629E /* UserModel.m in Sources */ = {isa = PBXBuildFile; fileRef = 7688437B1CAA37EF00D8629E /* UserModel.m */; }; 768843931CAA37EF00D8629E /* UserModel.m in Sources */ = {isa = PBXBuildFile; fileRef = 7688437B1CAA37EF00D8629E /* UserModel.m */; };
768843961CAA37EF00D8629E /* Utilities.m in Sources */ = {isa = PBXBuildFile; fileRef = 7688437E1CAA37EF00D8629E /* Utilities.m */; }; 768843961CAA37EF00D8629E /* Utilities.m in Sources */ = {isa = PBXBuildFile; fileRef = 7688437E1CAA37EF00D8629E /* Utilities.m */; };
B13424EE6D36C2EC5D1030B6 /* libPods-Sample.a in Frameworks */ = {isa = PBXBuildFile; fileRef = AD5DDA0A29B0F32AA5CC47BA /* libPods-Sample.a */; }; B13424EE6D36C2EC5D1030B6 /* libPods-Sample.a in Frameworks */ = {isa = PBXBuildFile; fileRef = AD5DDA0A29B0F32AA5CC47BA /* libPods-Sample.a */; };
CC00D1571E15912F004E5502 /* PhotoFeedListKitViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = CC00D1561E15912F004E5502 /* PhotoFeedListKitViewController.m */; };
CC5369AC1E15925200FAD348 /* PhotoFeedSectionController.m in Sources */ = {isa = PBXBuildFile; fileRef = CC5369AB1E15925200FAD348 /* PhotoFeedSectionController.m */; };
CC5532171E15CC1E0011C01F /* ASCollectionSectionController.m in Sources */ = {isa = PBXBuildFile; fileRef = CC5532161E15CC1E0011C01F /* ASCollectionSectionController.m */; };
CC6350BB1E1C482D002BC613 /* TailLoadingNode.m in Sources */ = {isa = PBXBuildFile; fileRef = CC6350BA1E1C482D002BC613 /* TailLoadingNode.m */; };
CC85250F1E36B392008EABE6 /* FeedHeaderNode.m in Sources */ = {isa = PBXBuildFile; fileRef = CC85250E1E36B392008EABE6 /* FeedHeaderNode.m */; };
/* End PBXBuildFile section */ /* End PBXBuildFile section */
/* Begin PBXFileReference section */ /* Begin PBXFileReference section */
@@ -80,6 +85,17 @@
7688437F1CAA37EF00D8629E /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; }; 7688437F1CAA37EF00D8629E /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
97A9B1BAF4265967672F9EA3 /* Pods-Sample.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Sample.debug.xcconfig"; path = "Pods/Target Support Files/Pods-Sample/Pods-Sample.debug.xcconfig"; sourceTree = "<group>"; }; 97A9B1BAF4265967672F9EA3 /* Pods-Sample.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Sample.debug.xcconfig"; path = "Pods/Target Support Files/Pods-Sample/Pods-Sample.debug.xcconfig"; sourceTree = "<group>"; };
AD5DDA0A29B0F32AA5CC47BA /* libPods-Sample.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-Sample.a"; sourceTree = BUILT_PRODUCTS_DIR; }; AD5DDA0A29B0F32AA5CC47BA /* libPods-Sample.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-Sample.a"; sourceTree = BUILT_PRODUCTS_DIR; };
CC00D1551E15912F004E5502 /* PhotoFeedListKitViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PhotoFeedListKitViewController.h; sourceTree = "<group>"; };
CC00D1561E15912F004E5502 /* PhotoFeedListKitViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PhotoFeedListKitViewController.m; sourceTree = "<group>"; };
CC5369AA1E15925200FAD348 /* PhotoFeedSectionController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PhotoFeedSectionController.h; sourceTree = "<group>"; };
CC5369AB1E15925200FAD348 /* PhotoFeedSectionController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PhotoFeedSectionController.m; sourceTree = "<group>"; };
CC5532111E159D770011C01F /* RefreshingSectionControllerType.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RefreshingSectionControllerType.h; sourceTree = "<group>"; };
CC5532151E15CC1E0011C01F /* ASCollectionSectionController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ASCollectionSectionController.h; sourceTree = "<group>"; };
CC5532161E15CC1E0011C01F /* ASCollectionSectionController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ASCollectionSectionController.m; sourceTree = "<group>"; };
CC6350B91E1C482D002BC613 /* TailLoadingNode.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TailLoadingNode.h; sourceTree = "<group>"; };
CC6350BA1E1C482D002BC613 /* TailLoadingNode.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = TailLoadingNode.m; sourceTree = "<group>"; };
CC85250D1E36B392008EABE6 /* FeedHeaderNode.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = FeedHeaderNode.h; sourceTree = "<group>"; };
CC85250E1E36B392008EABE6 /* FeedHeaderNode.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = FeedHeaderNode.m; sourceTree = "<group>"; };
D09B5DF0BFB37583DE8F3142 /* Pods-Sample.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Sample.release.xcconfig"; path = "Pods/Target Support Files/Pods-Sample/Pods-Sample.release.xcconfig"; sourceTree = "<group>"; }; D09B5DF0BFB37583DE8F3142 /* Pods-Sample.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Sample.release.xcconfig"; path = "Pods/Target Support Files/Pods-Sample/Pods-Sample.release.xcconfig"; sourceTree = "<group>"; };
/* End PBXFileReference section */ /* End PBXFileReference section */
@@ -169,6 +185,7 @@
children = ( children = (
767A5F161CAA3D96004CDA8D /* UIKit */, 767A5F161CAA3D96004CDA8D /* UIKit */,
767A5F151CAA3D90004CDA8D /* ASDK */, 767A5F151CAA3D90004CDA8D /* ASDK */,
CC00D1581E159132004E5502 /* ASDK-ListKit */,
); );
name = Controller; name = Controller;
sourceTree = "<group>"; sourceTree = "<group>";
@@ -239,6 +256,10 @@
767A5F1A1CAA3DBF004CDA8D /* ASDK */ = { 767A5F1A1CAA3DBF004CDA8D /* ASDK */ = {
isa = PBXGroup; isa = PBXGroup;
children = ( children = (
CC85250D1E36B392008EABE6 /* FeedHeaderNode.h */,
CC85250E1E36B392008EABE6 /* FeedHeaderNode.m */,
CC6350B91E1C482D002BC613 /* TailLoadingNode.h */,
CC6350BA1E1C482D002BC613 /* TailLoadingNode.m */,
7688435B1CAA37EF00D8629E /* PhotoCellNode.h */, 7688435B1CAA37EF00D8629E /* PhotoCellNode.h */,
768843731CAA37EF00D8629E /* PhotoCellNode.m */, 768843731CAA37EF00D8629E /* PhotoCellNode.m */,
768843541CAA37EF00D8629E /* CommentsNode.h */, 768843541CAA37EF00D8629E /* CommentsNode.h */,
@@ -247,6 +268,20 @@
name = ASDK; name = ASDK;
sourceTree = "<group>"; sourceTree = "<group>";
}; };
CC00D1581E159132004E5502 /* ASDK-ListKit */ = {
isa = PBXGroup;
children = (
CC5532111E159D770011C01F /* RefreshingSectionControllerType.h */,
CC00D1551E15912F004E5502 /* PhotoFeedListKitViewController.h */,
CC00D1561E15912F004E5502 /* PhotoFeedListKitViewController.m */,
CC5369AA1E15925200FAD348 /* PhotoFeedSectionController.h */,
CC5369AB1E15925200FAD348 /* PhotoFeedSectionController.m */,
CC5532151E15CC1E0011C01F /* ASCollectionSectionController.h */,
CC5532161E15CC1E0011C01F /* ASCollectionSectionController.m */,
);
name = "ASDK-ListKit";
sourceTree = "<group>";
};
/* End PBXGroup section */ /* End PBXGroup section */
/* Begin PBXNativeTarget section */ /* Begin PBXNativeTarget section */
@@ -378,15 +413,20 @@
768843831CAA37EF00D8629E /* CommentsNode.m in Sources */, 768843831CAA37EF00D8629E /* CommentsNode.m in Sources */,
768843961CAA37EF00D8629E /* Utilities.m in Sources */, 768843961CAA37EF00D8629E /* Utilities.m in Sources */,
768843931CAA37EF00D8629E /* UserModel.m in Sources */, 768843931CAA37EF00D8629E /* UserModel.m in Sources */,
CC5532171E15CC1E0011C01F /* ASCollectionSectionController.m in Sources */,
768843801CAA37EF00D8629E /* AppDelegate.m in Sources */, 768843801CAA37EF00D8629E /* AppDelegate.m in Sources */,
768843811CAA37EF00D8629E /* CommentFeedModel.m in Sources */, 768843811CAA37EF00D8629E /* CommentFeedModel.m in Sources */,
7688438E1CAA37EF00D8629E /* PhotoFeedNodeController.m in Sources */, 7688438E1CAA37EF00D8629E /* PhotoFeedNodeController.m in Sources */,
CC6350BB1E1C482D002BC613 /* TailLoadingNode.m in Sources */,
CC85250F1E36B392008EABE6 /* FeedHeaderNode.m in Sources */,
768843841CAA37EF00D8629E /* CommentView.m in Sources */, 768843841CAA37EF00D8629E /* CommentView.m in Sources */,
768843881CAA37EF00D8629E /* LocationModel.m in Sources */, 768843881CAA37EF00D8629E /* LocationModel.m in Sources */,
768843901CAA37EF00D8629E /* PhotoModel.m in Sources */, 768843901CAA37EF00D8629E /* PhotoModel.m in Sources */,
768843911CAA37EF00D8629E /* PhotoTableViewCell.m in Sources */, 768843911CAA37EF00D8629E /* PhotoTableViewCell.m in Sources */,
CC00D1571E15912F004E5502 /* PhotoFeedListKitViewController.m in Sources */,
7688438B1CAA37EF00D8629E /* PhotoCellNode.m in Sources */, 7688438B1CAA37EF00D8629E /* PhotoCellNode.m in Sources */,
7688438D1CAA37EF00D8629E /* PhotoFeedModel.m in Sources */, 7688438D1CAA37EF00D8629E /* PhotoFeedModel.m in Sources */,
CC5369AC1E15925200FAD348 /* PhotoFeedSectionController.m in Sources */,
768843851CAA37EF00D8629E /* ImageURLModel.m in Sources */, 768843851CAA37EF00D8629E /* ImageURLModel.m in Sources */,
); );
runOnlyForDeploymentPostprocessing = 0; runOnlyForDeploymentPostprocessing = 0;

View File

@@ -0,0 +1,10 @@
<?xml version="1.0" encoding="UTF-8"?>
<Workspace
version = "1.0">
<FileRef
location = "group:Sample.xcodeproj">
</FileRef>
<FileRef
location = "group:Pods/Pods.xcodeproj">
</FileRef>
</Workspace>

View File

@@ -0,0 +1,28 @@
//
// ASCollectionSectionController.h
// Sample
//
// Created by Adlai Holler on 12/29/16.
// Copyright © 2016 Facebook. All rights reserved.
//
#import <IGListKit/IGListKit.h>
NS_ASSUME_NONNULL_BEGIN
@interface ASCollectionSectionController : IGListSectionController
/**
* The items managed by this section controller.
*/
@property (nonatomic, strong, readonly) NSArray<id<IGListDiffable>> *items;
- (void)setItems:(NSArray<id<IGListDiffable>> *)newItems
animated:(BOOL)animated
completion:(nullable void(^)())completion;
- (NSInteger)numberOfItems;
@end
NS_ASSUME_NONNULL_END

View File

@@ -0,0 +1,79 @@
//
// ASCollectionSectionController.m
// Sample
//
// Created by Adlai Holler on 12/29/16.
// Copyright © 2016 Facebook. All rights reserved.
//
#import "ASCollectionSectionController.h"
#import <AsyncDisplayKit/AsyncDisplayKit.h>
@interface ASCollectionSectionController ()
@property (nonatomic, strong, readonly) dispatch_queue_t diffingQueue;
/// The items that have been diffed and are waiting to be submitted to the collection view.
/// Should always be accessed on the diffing queue, and should never be accessed
/// before the initial items are read (in -numberOfItems).
@property (nonatomic, copy) NSArray *pendingItems;
@property (nonatomic) BOOL initialItemsRead;
@end
@implementation ASCollectionSectionController
@synthesize diffingQueue = _diffingQueue;
- (NSInteger)numberOfItems
{
if (_initialItemsRead == NO) {
_pendingItems = self.items;
_initialItemsRead = YES;
}
return self.items.count;
}
- (dispatch_queue_t)diffingQueue
{
if (_diffingQueue == nil) {
_diffingQueue = dispatch_queue_create("ASCollectionSectionController.diffingQueue", DISPATCH_QUEUE_SERIAL);
}
return _diffingQueue;
}
- (void)setItems:(NSArray *)newItems animated:(BOOL)animated completion:(void(^)())completion
{
ASDisplayNodeAssertMainThread();
newItems = [newItems copy];
if (!self.initialItemsRead) {
_items = newItems;
if (completion) {
completion();
}
return;
}
BOOL wasEmpty = (self.items.count == 0);
dispatch_async(self.diffingQueue, ^{
IGListIndexSetResult *result = IGListDiff(self.pendingItems, newItems, IGListDiffPointerPersonality);
self.pendingItems = newItems;
dispatch_async(dispatch_get_main_queue(), ^{
id<IGListCollectionContext> ctx = self.collectionContext;
[ctx performBatchAnimated:animated updates:^{
[ctx insertInSectionController:(id)self atIndexes:result.inserts];
[ctx deleteInSectionController:(id)self atIndexes:result.deletes];
_items = newItems;
} completion:^(BOOL finished) {
if (completion) {
completion();
}
// WORKAROUND for https://github.com/Instagram/IGListKit/issues/378
if (wasEmpty) {
[(IGListAdapter *)ctx performUpdatesAnimated:NO completion:nil];
}
}];
});
});
}
@end

View File

@@ -20,6 +20,7 @@
#import "AppDelegate.h" #import "AppDelegate.h"
#import "PhotoFeedViewController.h" #import "PhotoFeedViewController.h"
#import "PhotoFeedNodeController.h" #import "PhotoFeedNodeController.h"
#import "PhotoFeedListKitViewController.h"
#import "WindowWithStatusBarUnderlay.h" #import "WindowWithStatusBarUnderlay.h"
#import "Utilities.h" #import "Utilities.h"
@@ -37,13 +38,19 @@
_window = [[WindowWithStatusBarUnderlay alloc] initWithFrame:[[UIScreen mainScreen] bounds]]; _window = [[WindowWithStatusBarUnderlay alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
_window.backgroundColor = [UIColor whiteColor]; _window.backgroundColor = [UIColor whiteColor];
// UIKit Home Feed viewController & navController // ASDK Home Feed viewController & navController
PhotoFeedNodeController *asdkHomeFeedVC = [[PhotoFeedNodeController alloc] init]; PhotoFeedNodeController *asdkHomeFeedVC = [[PhotoFeedNodeController alloc] init];
UINavigationController *asdkHomeFeedNavCtrl = [[UINavigationController alloc] initWithRootViewController:asdkHomeFeedVC]; UINavigationController *asdkHomeFeedNavCtrl = [[UINavigationController alloc] initWithRootViewController:asdkHomeFeedVC];
asdkHomeFeedNavCtrl.tabBarItem = [[UITabBarItem alloc] initWithTitle:@"ASDK" image:[UIImage imageNamed:@"home"] tag:0]; asdkHomeFeedNavCtrl.tabBarItem = [[UITabBarItem alloc] initWithTitle:@"ASDK" image:[UIImage imageNamed:@"home"] tag:0];
asdkHomeFeedNavCtrl.hidesBarsOnSwipe = YES; asdkHomeFeedNavCtrl.hidesBarsOnSwipe = YES;
// ASDK Home Feed viewController & navController // ListKit Home Feed viewController & navController
PhotoFeedListKitViewController *listKitHomeFeedVC = [[PhotoFeedListKitViewController alloc] init];
UINavigationController *listKitHomeFeedNavCtrl = [[UINavigationController alloc] initWithRootViewController:listKitHomeFeedVC];
listKitHomeFeedNavCtrl.tabBarItem = [[UITabBarItem alloc] initWithTitle:@"ListKit" image:[UIImage imageNamed:@"home"] tag:0];
listKitHomeFeedNavCtrl.hidesBarsOnSwipe = YES;
// UIKit Home Feed viewController & navController
PhotoFeedViewController *uikitHomeFeedVC = [[PhotoFeedViewController alloc] init]; PhotoFeedViewController *uikitHomeFeedVC = [[PhotoFeedViewController alloc] init];
UINavigationController *uikitHomeFeedNavCtrl = [[UINavigationController alloc] initWithRootViewController:uikitHomeFeedVC]; UINavigationController *uikitHomeFeedNavCtrl = [[UINavigationController alloc] initWithRootViewController:uikitHomeFeedVC];
uikitHomeFeedNavCtrl.tabBarItem = [[UITabBarItem alloc] initWithTitle:@"UIKit" image:[UIImage imageNamed:@"home"] tag:0]; uikitHomeFeedNavCtrl.tabBarItem = [[UITabBarItem alloc] initWithTitle:@"UIKit" image:[UIImage imageNamed:@"home"] tag:0];
@@ -51,7 +58,7 @@
// UITabBarController // UITabBarController
UITabBarController *tabBarController = [[UITabBarController alloc] init]; UITabBarController *tabBarController = [[UITabBarController alloc] init];
tabBarController.viewControllers = @[uikitHomeFeedNavCtrl, asdkHomeFeedNavCtrl]; tabBarController.viewControllers = @[uikitHomeFeedNavCtrl, asdkHomeFeedNavCtrl, listKitHomeFeedNavCtrl];
tabBarController.selectedViewController = asdkHomeFeedNavCtrl; tabBarController.selectedViewController = asdkHomeFeedNavCtrl;
tabBarController.delegate = self; tabBarController.delegate = self;
[[UITabBar appearance] setTintColor:[UIColor darkBlueColor]]; [[UITabBar appearance] setTintColor:[UIColor darkBlueColor]];

View File

@@ -0,0 +1,13 @@
//
// FeedHeaderNode.h
// Sample
//
// Created by Adlai Holler on 1/23/17.
// Copyright © 2017 Facebook. All rights reserved.
//
#import <AsyncDisplayKit/AsyncDisplayKit.h>
@interface FeedHeaderNode : ASCellNode
@end

View File

@@ -0,0 +1,35 @@
//
// FeedHeaderNode.m
// Sample
//
// Created by Adlai Holler on 1/23/17.
// Copyright © 2017 Facebook. All rights reserved.
//
#import "FeedHeaderNode.h"
#import "Utilities.h"
static UIEdgeInsets kFeedHeaderInset = { .top = 20, .bottom = 20, .left = 10, .right = 10 };
@interface FeedHeaderNode ()
@property (nonatomic, strong, readonly) ASTextNode *textNode;
@end
@implementation FeedHeaderNode
- (instancetype)init
{
if (self = [super init]) {
_textNode = [[ASTextNode alloc] init];
self.automaticallyManagesSubnodes = YES;
_textNode.attributedText = [NSAttributedString attributedStringWithString:@"Latest Posts" fontSize:18 color:[UIColor darkGrayColor] firstWordColor:nil];
}
return self;
}
- (ASLayoutSpec *)layoutSpecThatFits:(ASSizeRange)constrainedSize
{
return [ASInsetLayoutSpec insetLayoutSpecWithInsets:kFeedHeaderInset child:_textNode];
}
@end

View File

@@ -0,0 +1,14 @@
//
// PhotoFeedListKitViewController.h
// Sample
//
// Created by Adlai Holler on 12/29/16.
// Copyright © 2016 Facebook. All rights reserved.
//
#import <AsyncDisplayKit/AsyncDisplayKit.h>
#import "AppDelegate.h"
@interface PhotoFeedListKitViewController<ASCollectionNode> : ASViewController <PhotoFeedControllerProtocol>
@end

View File

@@ -0,0 +1,106 @@
//
// PhotoFeedListKitViewController.m
// Sample
//
// Created by Adlai Holler on 12/29/16.
// Copyright © 2016 Facebook. All rights reserved.
//
#import "PhotoFeedListKitViewController.h"
#import <IGListKit/IGListKit.h>
#import "PhotoFeedModel.h"
#import "PhotoFeedSectionController.h"
#import "RefreshingSectionControllerType.h"
@interface PhotoFeedListKitViewController () <IGListAdapterDataSource, ASCollectionDelegate>
@property (nonatomic, strong) IGListAdapter *listAdapter;
@property (nonatomic, strong) PhotoFeedModel *photoFeed;
@property (nonatomic, strong, readonly) ASCollectionNode *collectionNode;
@property (nonatomic, strong, readonly) UIActivityIndicatorView *spinner;
@property (nonatomic, strong, readonly) UIRefreshControl *refreshCtrl;
@end
@implementation PhotoFeedListKitViewController
@synthesize spinner = _spinner;
- (instancetype)init
{
UICollectionViewFlowLayout *layout = [[UICollectionViewFlowLayout alloc] init];
ASCollectionNode *node = [[ASCollectionNode alloc] initWithCollectionViewLayout:layout];
if (self = [super initWithNode:node]) {
CGRect screenRect = [[UIScreen mainScreen] bounds];
CGFloat screenScale = [[UIScreen mainScreen] scale];
CGSize screenWidthImageSize = CGSizeMake(screenRect.size.width * screenScale, screenRect.size.width * screenScale);
_photoFeed = [[PhotoFeedModel alloc] initWithPhotoFeedModelType:PhotoFeedModelTypePopular imageSize:screenWidthImageSize];
IGListAdapterUpdater *updater = [[IGListAdapterUpdater alloc] init];
_listAdapter = [[IGListAdapter alloc] initWithUpdater:updater viewController:self workingRangeSize:0];
_listAdapter.dataSource = self;
[_listAdapter setASDKCollectionNode:self.collectionNode];
}
return self;
}
- (void)viewDidLoad
{
[super viewDidLoad];
self.collectionNode.view.alwaysBounceVertical = YES;
_refreshCtrl = [[UIRefreshControl alloc] init];
[_refreshCtrl addTarget:self action:@selector(refreshFeed) forControlEvents:UIControlEventValueChanged];
[self.collectionNode.view addSubview:_refreshCtrl];
_spinner = [[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleGray];
}
- (ASCollectionNode *)collectionNode
{
return self.node;
}
- (void)resetAllData
{
// nop, not used currently
}
- (void)refreshFeed
{
// Ask the first section controller to do the refreshing.
id<RefreshingSectionControllerType> secCtrl = [self.listAdapter sectionControllerForObject:self.photoFeed];
if ([secCtrl conformsToProtocol:@protocol(RefreshingSectionControllerType)]) {
[secCtrl refreshContentWithCompletion:^{
[self.refreshCtrl endRefreshing];
}];
}
}
- (UIActivityIndicatorView *)spinner
{
if (_spinner == nil) {
_spinner = [[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleGray];
[_spinner startAnimating];
}
return _spinner;
}
#pragma mark - IGListAdapterDataSource
- (NSArray<id <IGListDiffable>> *)objectsForListAdapter:(IGListAdapter *)listAdapter
{
return @[ self.photoFeed ];
}
- (UIView *)emptyViewForListAdapter:(IGListAdapter *)listAdapter
{
return self.spinner;
}
- (IGListSectionController <IGListSectionType> *)listAdapter:(IGListAdapter *)listAdapter sectionControllerForObject:(id)object
{
if ([object isKindOfClass:[PhotoFeedModel class]]) {
return [[PhotoFeedSectionController alloc] init];
} else {
ASDisplayNodeFailAssert(@"Only supports objects of class PhotoFeedModel.");
return nil;
}
}
@end

View File

@@ -18,6 +18,7 @@
// //
#import "PhotoModel.h" #import "PhotoModel.h"
#import <IGListKit/IGListKit.h>
typedef NS_ENUM(NSInteger, PhotoFeedModelType) { typedef NS_ENUM(NSInteger, PhotoFeedModelType) {
PhotoFeedModelTypePopular, PhotoFeedModelTypePopular,
@@ -25,11 +26,13 @@ typedef NS_ENUM(NSInteger, PhotoFeedModelType) {
PhotoFeedModelTypeUserPhotos PhotoFeedModelTypeUserPhotos
}; };
@interface PhotoFeedModel : NSObject @interface PhotoFeedModel : NSObject <IGListDiffable>
- (instancetype)init NS_UNAVAILABLE; - (instancetype)init NS_UNAVAILABLE;
- (instancetype)initWithPhotoFeedModelType:(PhotoFeedModelType)type imageSize:(CGSize)size NS_DESIGNATED_INITIALIZER; - (instancetype)initWithPhotoFeedModelType:(PhotoFeedModelType)type imageSize:(CGSize)size NS_DESIGNATED_INITIALIZER;
@property (nonatomic, readonly) NSArray<PhotoModel *> *photos;
- (NSUInteger)totalNumberOfPhotos; - (NSUInteger)totalNumberOfPhotos;
- (NSUInteger)numberOfItemsInFeed; - (NSUInteger)numberOfItemsInFeed;
- (PhotoModel *)objectAtIndex:(NSUInteger)index; - (PhotoModel *)objectAtIndex:(NSUInteger)index;

View File

@@ -47,13 +47,6 @@
NSUInteger _userID; NSUInteger _userID;
} }
#pragma mark - Properties
- (NSMutableArray *)photos
{
return _photos;
}
#pragma mark - Lifecycle #pragma mark - Lifecycle
- (instancetype)initWithPhotoFeedModelType:(PhotoFeedModelType)type imageSize:(CGSize)size - (instancetype)initWithPhotoFeedModelType:(PhotoFeedModelType)type imageSize:(CGSize)size
@@ -92,6 +85,11 @@
#pragma mark - Instance Methods #pragma mark - Instance Methods
- (NSArray *)photos
{
return [_photos copy];
}
- (NSUInteger)totalNumberOfPhotos - (NSUInteger)totalNumberOfPhotos
{ {
return _totalItems; return _totalItems;
@@ -186,10 +184,13 @@
// early return if reached end of pages // early return if reached end of pages
if (_totalPages) { if (_totalPages) {
if (_currentPage == _totalPages) { if (_currentPage == _totalPages) {
if (block){
block(@[]);
}
return; return;
} }
} }
NSUInteger numPhotos = (numResults < 100) ? numResults : 100; NSUInteger numPhotos = (numResults < 100) ? numResults : 100;
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
@@ -246,4 +247,16 @@
}); });
} }
#pragma mark - IGListDiffable
- (id<NSObject>)diffIdentifier
{
return self;
}
- (BOOL)isEqualToDiffableObject:(id<IGListDiffable>)object
{
return self == object;
}
@end @end

View File

@@ -0,0 +1,24 @@
//
// PhotoFeedSectionController.h
// Sample
//
// Created by Adlai Holler on 12/29/16.
// Copyright © 2016 Facebook. All rights reserved.
//
#import <IGListKit/IGListKit.h>
#import <AsyncDisplayKit/AsyncDisplayKit.h>
#import "RefreshingSectionControllerType.h"
#import "ASCollectionSectionController.h"
@class PhotoFeedModel;
NS_ASSUME_NONNULL_BEGIN
@interface PhotoFeedSectionController : ASCollectionSectionController <IGListSectionType, ASSectionController, RefreshingSectionControllerType>
@property (nonatomic, strong, nullable) PhotoFeedModel *photoFeed;
@end
NS_ASSUME_NONNULL_END

View File

@@ -0,0 +1,122 @@
//
// PhotoFeedSectionController.m
// Sample
//
// Created by Adlai Holler on 12/29/16.
// Copyright © 2016 Facebook. All rights reserved.
//
#import "PhotoFeedSectionController.h"
#import "PhotoFeedModel.h"
#import "PhotoModel.h"
#import "PhotoCellNode.h"
#import "TailLoadingNode.h"
#import "FeedHeaderNode.h"
@interface PhotoFeedSectionController () <ASSupplementaryNodeSource, IGListSupplementaryViewSource>
@property (nonatomic, strong) NSString *paginatingSpinner;
@end
@implementation PhotoFeedSectionController
- (instancetype)init
{
if (self = [super init]) {
_paginatingSpinner = @"Paginating Spinner";
self.supplementaryViewSource = self;
}
return self;
}
#pragma mark - IGListSectionType
- (void)didUpdateToObject:(id)object
{
_photoFeed = object;
[self setItems:_photoFeed.photos animated:NO completion:nil];
}
ASIGSectionControllerSizeForItemImplementation;
ASIGSectionControllerCellForIndexImplementation;
- (void)didSelectItemAtIndex:(NSInteger)index
{
// nop
}
#pragma mark - ASSectionController
- (ASCellNodeBlock)nodeBlockForItemAtIndex:(NSInteger)index
{
id object = self.items[index];
// this will be executed on a background thread - important to make sure it's thread safe
ASCellNode *(^nodeBlock)() = nil;
if (object == _paginatingSpinner) {
nodeBlock = ^{
return [[TailLoadingNode alloc] init];
};
} else if ([object isKindOfClass:[PhotoModel class]]) {
PhotoModel *photoModel = object;
nodeBlock = ^{
PhotoCellNode *cellNode = [[PhotoCellNode alloc] initWithPhotoObject:photoModel];
return cellNode;
};
}
return nodeBlock;
}
- (void)beginBatchFetchWithContext:(ASBatchContext *)context
{
// Immediately add the loading spinner if needed.
if (self.items.count > 0) {
NSArray *newItems = [self.items arrayByAddingObject:_paginatingSpinner];
[self setItems:newItems animated:NO completion:nil];
}
// Start the fetch, then update the items (removing the spinner) when they are loaded.
[_photoFeed requestPageWithCompletionBlock:^(NSArray *newPhotos){
[self setItems:_photoFeed.photos animated:NO completion:^{
[context completeBatchFetching:YES];
}];
} numResultsToReturn:20];
}
#pragma mark - RefreshingSectionControllerType
- (void)refreshContentWithCompletion:(void(^)())completion
{
[_photoFeed refreshFeedWithCompletionBlock:^(NSArray *addedItems) {
[self setItems:_photoFeed.photos animated:YES completion:completion];
} numResultsToReturn:4];
}
#pragma mark - ASSupplementaryNodeSource
- (ASCellNode *)nodeForSupplementaryElementOfKind:(NSString *)elementKind atIndex:(NSInteger)index
{
ASDisplayNodeAssert([elementKind isEqualToString:UICollectionElementKindSectionHeader], nil);
return [[FeedHeaderNode alloc] init];
}
- (ASSizeRange)sizeRangeForSupplementaryElementOfKind:(NSString *)elementKind atIndex:(NSInteger)index
{
if ([elementKind isEqualToString:UICollectionElementKindSectionHeader]) {
return ASSizeRangeUnconstrained;
} else {
return ASSizeRangeZero;
}
}
#pragma mark - IGListSupplementaryViewSource
- (NSArray<NSString *> *)supportedElementKinds
{
return @[ UICollectionElementKindSectionHeader ];
}
ASIGSupplementarySourceViewForSupplementaryElementImplementation(self);
ASIGSupplementarySourceSizeForSupplementaryElementImplementation;
@end

View File

@@ -17,12 +17,12 @@
// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. // CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
// //
#import "CoreGraphics/CoreGraphics.h"
#import "UserModel.h" #import "UserModel.h"
#import "LocationModel.h" #import "LocationModel.h"
#import "CommentFeedModel.h" #import "CommentFeedModel.h"
#import <IGListKit/IGListKit.h>
@interface PhotoModel : NSObject @interface PhotoModel : NSObject <IGListDiffable>
@property (nonatomic, strong, readonly) NSURL *URL; @property (nonatomic, strong, readonly) NSURL *URL;
@property (nonatomic, strong, readonly) NSString *photoID; @property (nonatomic, strong, readonly) NSString *photoID;

View File

@@ -83,11 +83,7 @@
- (NSAttributedString *)likesAttributedStringWithFontSize:(CGFloat)size - (NSAttributedString *)likesAttributedStringWithFontSize:(CGFloat)size
{ {
NSNumberFormatter *formatter = [[NSNumberFormatter alloc] init]; NSString *likesString = [NSString stringWithFormat:@"♥︎ %lu likes", (unsigned long)_likesCount];
[formatter setNumberStyle:NSNumberFormatterDecimalStyle];
NSString *formattedLikesNumber = [formatter stringFromNumber:[[NSNumber alloc] initWithUnsignedInteger:self.likesCount]];
NSString *likesString = [NSString stringWithFormat:@"♥︎ %@ likes", formattedLikesNumber];
return [NSAttributedString attributedStringWithString:likesString fontSize:size color:[UIColor darkBlueColor] firstWordColor:nil]; return [NSAttributedString attributedStringWithString:likesString fontSize:size color:[UIColor darkBlueColor] firstWordColor:nil];
} }
@@ -102,4 +98,14 @@
return [NSString stringWithFormat:@"%@ - %@", _photoID, _descriptionText]; return [NSString stringWithFormat:@"%@ - %@", _photoID, _descriptionText];
} }
@end - (id<NSObject>)diffIdentifier
{
return self.photoID;
}
- (BOOL)isEqualToDiffableObject:(id<IGListDiffable>)object
{
return [self isEqual:object];
}
@end

View File

@@ -0,0 +1,19 @@
//
// RefreshingSectionControllerType.h
// Sample
//
// Created by Adlai Holler on 12/29/16.
// Copyright © 2016 Facebook. All rights reserved.
//
#import <IGListKit/IGListKit.h>
NS_ASSUME_NONNULL_BEGIN
@protocol RefreshingSectionControllerType <IGListSectionType>
- (void)refreshContentWithCompletion:(nullable void(^)())completion;
@end
NS_ASSUME_NONNULL_END

View File

@@ -0,0 +1,17 @@
//
// TailLoadingNode.h
// Sample
//
// Created by Adlai Holler on 1/3/17.
// Copyright © 2017 Facebook. All rights reserved.
//
#import <AsyncDisplayKit/AsyncDisplayKit.h>
/**
* A node that shows a UIActivityIndicatorView, useful for putting at the end of a
* list while the next page is loading.
*/
@interface TailLoadingNode : ASCellNode
@end

View File

@@ -0,0 +1,35 @@
//
// TailLoadingNode.m
// Sample
//
// Created by Adlai Holler on 1/3/17.
// Copyright © 2017 Facebook. All rights reserved.
//
#import "TailLoadingNode.h"
@interface TailLoadingNode ()
@property (nonatomic, strong) ASDisplayNode *activityIndicatorNode;
@end
@implementation TailLoadingNode
- (instancetype)init
{
if (self = [super init]) {
_activityIndicatorNode = [[ASDisplayNode alloc] initWithViewBlock:^{
UIActivityIndicatorView *v = [[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleGray];
[v startAnimating];
return v;
}];
self.style.height = ASDimensionMake(100);
}
return self;
}
- (ASLayoutSpec *)layoutSpecThatFits:(ASSizeRange)constrainedSize
{
return [ASCenterLayoutSpec centerLayoutSpecWithCenteringOptions:ASCenterLayoutSpecCenteringXY sizingOptions:ASCenterLayoutSpecSizingOptionMinimumXY child:self.activityIndicatorNode];
}
@end