Merge pull request #1160 from Adlai-Holler/AHUpdateSwiftExample

[Swift] Update Swift Example, resolve build issue with some Swift projects.
This commit is contained in:
appleguy 2016-02-02 15:57:40 -08:00
commit f1e000906d
11 changed files with 232 additions and 75 deletions

View File

@ -13,13 +13,19 @@ Pod::Spec.new do |spec|
'AsyncDisplayKit/*.h', 'AsyncDisplayKit/*.h',
'AsyncDisplayKit/Details/**/*.h', 'AsyncDisplayKit/Details/**/*.h',
'AsyncDisplayKit/Layout/*.h', 'AsyncDisplayKit/Layout/*.h',
'AsyncDisplayKit/TextKit/*.h', 'Base/*.h',
'Base/*.h' 'AsyncDisplayKit/TextKit/ASTextNodeTypes.h'
] ]
spec.source_files = [ spec.source_files = [
'AsyncDisplayKit/**/*.{h,m,mm}', 'AsyncDisplayKit/**/*.{h,m,mm}',
'Base/*.{h,m}' 'Base/*.{h,m}',
# Most TextKit components are not public because the C++ content
# in the headers will cause build errors when using
# `use_frameworks!` on 0.39.0 & Swift 2.1.
# See https://github.com/facebook/AsyncDisplayKit/issues/1153
'AsyncDisplayKit/TextKit/*.h',
] ]
spec.frameworks = 'AssetsLibrary' spec.frameworks = 'AssetsLibrary'

View File

@ -165,28 +165,24 @@ static const NSInteger kMaxLitterSize = 100; // max number of kitten cell
- (void)tableView:(UITableView *)tableView willBeginBatchFetchWithContext:(ASBatchContext *)context - (void)tableView:(UITableView *)tableView willBeginBatchFetchWithContext:(ASBatchContext *)context
{ {
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(1 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
sleep(1); // populate a new array of random-sized kittens
dispatch_async(dispatch_get_main_queue(), ^{ NSArray *moarKittens = [self createLitterWithSize:kLitterBatchSize];
// populate a new array of random-sized kittens
NSArray *moarKittens = [self createLitterWithSize:kLitterBatchSize];
NSMutableArray *indexPaths = [[NSMutableArray alloc] init]; NSMutableArray *indexPaths = [[NSMutableArray alloc] init];
// find number of kittens in the data source and create their indexPaths // find number of kittens in the data source and create their indexPaths
NSInteger existingRows = _kittenDataSource.count + 1; NSInteger existingRows = _kittenDataSource.count + 1;
for (NSInteger i = 0; i < moarKittens.count; i++) { for (NSInteger i = 0; i < moarKittens.count; i++) {
[indexPaths addObject:[NSIndexPath indexPathForRow:existingRows + i inSection:0]]; [indexPaths addObject:[NSIndexPath indexPathForRow:existingRows + i inSection:0]];
} }
// add new kittens to the data source & notify table of new indexpaths // add new kittens to the data source & notify table of new indexpaths
[_kittenDataSource addObjectsFromArray:moarKittens]; [_kittenDataSource addObjectsFromArray:moarKittens];
[tableView insertRowsAtIndexPaths:indexPaths withRowAnimation:UITableViewRowAnimationFade]; [tableView insertRowsAtIndexPaths:indexPaths withRowAnimation:UITableViewRowAnimationFade];
[context completeBatchFetching:YES]; [context completeBatchFetching:YES];
});
}); });
} }

View File

@ -1,3 +1,6 @@
source 'https://github.com/CocoaPods/Specs.git' source 'https://github.com/CocoaPods/Specs.git'
platform :ios, '8.0' platform :ios, '8.0'
use_frameworks!
pod 'AsyncDisplayKit', :path => '../..' pod 'AsyncDisplayKit', :path => '../..'

View File

@ -10,9 +10,10 @@
050E7C7419D22E19004363C2 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 050E7C7319D22E19004363C2 /* AppDelegate.swift */; }; 050E7C7419D22E19004363C2 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 050E7C7319D22E19004363C2 /* AppDelegate.swift */; };
050E7C7619D22E19004363C2 /* ViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 050E7C7519D22E19004363C2 /* ViewController.swift */; }; 050E7C7619D22E19004363C2 /* ViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 050E7C7519D22E19004363C2 /* ViewController.swift */; };
05DDD8DB19D2336300013C30 /* Default-568h@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = 05DDD8DA19D2336300013C30 /* Default-568h@2x.png */; }; 05DDD8DB19D2336300013C30 /* Default-568h@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = 05DDD8DA19D2336300013C30 /* Default-568h@2x.png */; };
4690009EF79C47BBA8FDBAD4 /* libPods.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 2ACC614D420B4E90B7EE3BCE /* libPods.a */; };
6C5053DB19EE266A00E385DE /* Default-667h@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = 6C5053D919EE266A00E385DE /* Default-667h@2x.png */; }; 6C5053DB19EE266A00E385DE /* Default-667h@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = 6C5053D919EE266A00E385DE /* Default-667h@2x.png */; };
6C5053DC19EE266A00E385DE /* Default-736h@3x.png in Resources */ = {isa = PBXBuildFile; fileRef = 6C5053DA19EE266A00E385DE /* Default-736h@3x.png */; }; 6C5053DC19EE266A00E385DE /* Default-736h@3x.png in Resources */ = {isa = PBXBuildFile; fileRef = 6C5053DA19EE266A00E385DE /* Default-736h@3x.png */; };
92E46E91A7D47AEC5B2B2F55 /* Pods.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 7FC29F18AE7C8C204A5CD4F2 /* Pods.framework */; };
CCB01CAB1C5FEA6E00CA64C4 /* TailLoadingCellNode.swift in Sources */ = {isa = PBXBuildFile; fileRef = CCB01CAA1C5FEA6E00CA64C4 /* TailLoadingCellNode.swift */; };
/* End PBXBuildFile section */ /* End PBXBuildFile section */
/* Begin PBXFileReference section */ /* Begin PBXFileReference section */
@ -21,11 +22,11 @@
050E7C7319D22E19004363C2 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = "<group>"; }; 050E7C7319D22E19004363C2 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = "<group>"; };
050E7C7519D22E19004363C2 /* ViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ViewController.swift; sourceTree = "<group>"; }; 050E7C7519D22E19004363C2 /* ViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ViewController.swift; sourceTree = "<group>"; };
05DDD8DA19D2336300013C30 /* Default-568h@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = "Default-568h@2x.png"; path = "../Default-568h@2x.png"; sourceTree = "<group>"; }; 05DDD8DA19D2336300013C30 /* Default-568h@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = "Default-568h@2x.png"; path = "../Default-568h@2x.png"; sourceTree = "<group>"; };
05DDD8DC19D2341D00013C30 /* AsyncDisplayKit-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "AsyncDisplayKit-Bridging-Header.h"; sourceTree = "<group>"; };
2ACC614D420B4E90B7EE3BCE /* libPods.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libPods.a; sourceTree = BUILT_PRODUCTS_DIR; };
6C5053D919EE266A00E385DE /* Default-667h@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "Default-667h@2x.png"; sourceTree = SOURCE_ROOT; }; 6C5053D919EE266A00E385DE /* Default-667h@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "Default-667h@2x.png"; sourceTree = SOURCE_ROOT; };
6C5053DA19EE266A00E385DE /* Default-736h@3x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "Default-736h@3x.png"; sourceTree = SOURCE_ROOT; }; 6C5053DA19EE266A00E385DE /* Default-736h@3x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "Default-736h@3x.png"; sourceTree = SOURCE_ROOT; };
7FC29F18AE7C8C204A5CD4F2 /* Pods.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods.framework; sourceTree = BUILT_PRODUCTS_DIR; };
841652076B3E9351337AA7C7 /* Pods.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = Pods.debug.xcconfig; path = "Pods/Target Support Files/Pods/Pods.debug.xcconfig"; sourceTree = "<group>"; }; 841652076B3E9351337AA7C7 /* Pods.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = Pods.debug.xcconfig; path = "Pods/Target Support Files/Pods/Pods.debug.xcconfig"; sourceTree = "<group>"; };
CCB01CAA1C5FEA6E00CA64C4 /* TailLoadingCellNode.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TailLoadingCellNode.swift; sourceTree = "<group>"; };
E3EE87D12CE3EF73FAE2EF02 /* Pods.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = Pods.release.xcconfig; path = "Pods/Target Support Files/Pods/Pods.release.xcconfig"; sourceTree = "<group>"; }; E3EE87D12CE3EF73FAE2EF02 /* Pods.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = Pods.release.xcconfig; path = "Pods/Target Support Files/Pods/Pods.release.xcconfig"; sourceTree = "<group>"; };
/* End PBXFileReference section */ /* End PBXFileReference section */
@ -34,7 +35,7 @@
isa = PBXFrameworksBuildPhase; isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647; buildActionMask = 2147483647;
files = ( files = (
4690009EF79C47BBA8FDBAD4 /* libPods.a in Frameworks */, 92E46E91A7D47AEC5B2B2F55 /* Pods.framework in Frameworks */,
); );
runOnlyForDeploymentPostprocessing = 0; runOnlyForDeploymentPostprocessing = 0;
}; };
@ -65,6 +66,7 @@
050E7C7019D22E19004363C2 /* Sample */ = { 050E7C7019D22E19004363C2 /* Sample */ = {
isa = PBXGroup; isa = PBXGroup;
children = ( children = (
CCB01CAA1C5FEA6E00CA64C4 /* TailLoadingCellNode.swift */,
050E7C7319D22E19004363C2 /* AppDelegate.swift */, 050E7C7319D22E19004363C2 /* AppDelegate.swift */,
050E7C7519D22E19004363C2 /* ViewController.swift */, 050E7C7519D22E19004363C2 /* ViewController.swift */,
050E7C7119D22E19004363C2 /* Supporting Files */, 050E7C7119D22E19004363C2 /* Supporting Files */,
@ -75,7 +77,6 @@
050E7C7119D22E19004363C2 /* Supporting Files */ = { 050E7C7119D22E19004363C2 /* Supporting Files */ = {
isa = PBXGroup; isa = PBXGroup;
children = ( children = (
05DDD8DC19D2341D00013C30 /* AsyncDisplayKit-Bridging-Header.h */,
050E7C7219D22E19004363C2 /* Info.plist */, 050E7C7219D22E19004363C2 /* Info.plist */,
05DDD8DA19D2336300013C30 /* Default-568h@2x.png */, 05DDD8DA19D2336300013C30 /* Default-568h@2x.png */,
6C5053D919EE266A00E385DE /* Default-667h@2x.png */, 6C5053D919EE266A00E385DE /* Default-667h@2x.png */,
@ -87,7 +88,7 @@
092C2001FE124604891D6E90 /* Frameworks */ = { 092C2001FE124604891D6E90 /* Frameworks */ = {
isa = PBXGroup; isa = PBXGroup;
children = ( children = (
2ACC614D420B4E90B7EE3BCE /* libPods.a */, 7FC29F18AE7C8C204A5CD4F2 /* Pods.framework */,
); );
name = Frameworks; name = Frameworks;
sourceTree = "<group>"; sourceTree = "<group>";
@ -113,6 +114,7 @@
050E7C6B19D22E19004363C2 /* Frameworks */, 050E7C6B19D22E19004363C2 /* Frameworks */,
050E7C6C19D22E19004363C2 /* Resources */, 050E7C6C19D22E19004363C2 /* Resources */,
941C5E41C54B4613A2D3B760 /* Copy Pods Resources */, 941C5E41C54B4613A2D3B760 /* Copy Pods Resources */,
1F5A9F09F5875F61862D0783 /* Embed Pods Frameworks */,
); );
buildRules = ( buildRules = (
); );
@ -131,7 +133,7 @@
attributes = { attributes = {
LastSwiftMigration = 0700; LastSwiftMigration = 0700;
LastSwiftUpdateCheck = 0700; LastSwiftUpdateCheck = 0700;
LastUpgradeCheck = 0600; LastUpgradeCheck = 0720;
ORGANIZATIONNAME = Facebook; ORGANIZATIONNAME = Facebook;
TargetAttributes = { TargetAttributes = {
050E7C6D19D22E19004363C2 = { 050E7C6D19D22E19004363C2 = {
@ -171,6 +173,21 @@
/* End PBXResourcesBuildPhase section */ /* End PBXResourcesBuildPhase section */
/* Begin PBXShellScriptBuildPhase section */ /* Begin PBXShellScriptBuildPhase section */
1F5A9F09F5875F61862D0783 /* Embed Pods Frameworks */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
);
inputPaths = (
);
name = "Embed Pods Frameworks";
outputPaths = (
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods/Pods-frameworks.sh\"\n";
showEnvVarsInLog = 0;
};
941C5E41C54B4613A2D3B760 /* Copy Pods Resources */ = { 941C5E41C54B4613A2D3B760 /* Copy Pods Resources */ = {
isa = PBXShellScriptBuildPhase; isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647; buildActionMask = 2147483647;
@ -208,6 +225,7 @@
isa = PBXSourcesBuildPhase; isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647; buildActionMask = 2147483647;
files = ( files = (
CCB01CAB1C5FEA6E00CA64C4 /* TailLoadingCellNode.swift in Sources */,
050E7C7619D22E19004363C2 /* ViewController.swift in Sources */, 050E7C7619D22E19004363C2 /* ViewController.swift in Sources */,
050E7C7419D22E19004363C2 /* AppDelegate.swift in Sources */, 050E7C7419D22E19004363C2 /* AppDelegate.swift in Sources */,
); );
@ -236,6 +254,7 @@
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
COPY_PHASE_STRIP = NO; COPY_PHASE_STRIP = NO;
ENABLE_STRICT_OBJC_MSGSEND = YES; ENABLE_STRICT_OBJC_MSGSEND = YES;
ENABLE_TESTABILITY = YES;
GCC_C_LANGUAGE_STANDARD = gnu99; GCC_C_LANGUAGE_STANDARD = gnu99;
GCC_DYNAMIC_NO_PIC = NO; GCC_DYNAMIC_NO_PIC = NO;
GCC_OPTIMIZATION_LEVEL = 0; GCC_OPTIMIZATION_LEVEL = 0;
@ -300,8 +319,8 @@
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
INFOPLIST_FILE = Sample/Info.plist; INFOPLIST_FILE = Sample/Info.plist;
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
PRODUCT_BUNDLE_IDENTIFIER = "com.facebook.AsyncDisplayKit.$(PRODUCT_NAME:rfc1034identifier)";
PRODUCT_NAME = "$(TARGET_NAME)"; PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_OBJC_BRIDGING_HEADER = "Sample/AsyncDisplayKit-Bridging-Header.h";
}; };
name = Debug; name = Debug;
}; };
@ -312,8 +331,8 @@
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
INFOPLIST_FILE = Sample/Info.plist; INFOPLIST_FILE = Sample/Info.plist;
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
PRODUCT_BUNDLE_IDENTIFIER = "com.facebook.AsyncDisplayKit.$(PRODUCT_NAME:rfc1034identifier)";
PRODUCT_NAME = "$(TARGET_NAME)"; PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_OBJC_BRIDGING_HEADER = "Sample/AsyncDisplayKit-Bridging-Header.h";
}; };
name = Release; name = Release;
}; };

View File

@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<Scheme <Scheme
LastUpgradeVersion = "0620" LastUpgradeVersion = "0720"
version = "1.3"> version = "1.3">
<BuildAction <BuildAction
parallelizeBuildables = "YES" parallelizeBuildables = "YES"
@ -23,10 +23,10 @@
</BuildActionEntries> </BuildActionEntries>
</BuildAction> </BuildAction>
<TestAction <TestAction
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB" selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB" selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
shouldUseLaunchSchemeArgsEnv = "YES" shouldUseLaunchSchemeArgsEnv = "YES">
buildConfiguration = "Debug">
<Testables> <Testables>
</Testables> </Testables>
<MacroExpansion> <MacroExpansion>
@ -38,15 +38,18 @@
ReferencedContainer = "container:Sample.xcodeproj"> ReferencedContainer = "container:Sample.xcodeproj">
</BuildableReference> </BuildableReference>
</MacroExpansion> </MacroExpansion>
<AdditionalOptions>
</AdditionalOptions>
</TestAction> </TestAction>
<LaunchAction <LaunchAction
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB" selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB" selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
launchStyle = "0" launchStyle = "0"
useCustomWorkingDirectory = "NO" useCustomWorkingDirectory = "NO"
buildConfiguration = "Debug"
ignoresPersistentStateOnLaunch = "NO" ignoresPersistentStateOnLaunch = "NO"
debugDocumentVersioning = "YES" debugDocumentVersioning = "YES"
debugServiceExtension = "internal"
allowLocationSimulation = "YES"> allowLocationSimulation = "YES">
<BuildableProductRunnable <BuildableProductRunnable
runnableDebuggingMode = "0"> runnableDebuggingMode = "0">
@ -62,10 +65,10 @@
</AdditionalOptions> </AdditionalOptions>
</LaunchAction> </LaunchAction>
<ProfileAction <ProfileAction
buildConfiguration = "Release"
shouldUseLaunchSchemeArgsEnv = "YES" shouldUseLaunchSchemeArgsEnv = "YES"
savedToolIdentifier = "" savedToolIdentifier = ""
useCustomWorkingDirectory = "NO" useCustomWorkingDirectory = "NO"
buildConfiguration = "Release"
debugDocumentVersioning = "YES"> debugDocumentVersioning = "YES">
<BuildableProductRunnable <BuildableProductRunnable
runnableDebuggingMode = "0"> runnableDebuggingMode = "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

@ -19,7 +19,7 @@ class AppDelegate: UIResponder, UIApplicationDelegate {
func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool { func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {
let window = UIWindow(frame: UIScreen.mainScreen().bounds) let window = UIWindow(frame: UIScreen.mainScreen().bounds)
window.backgroundColor = UIColor.whiteColor() window.backgroundColor = UIColor.whiteColor()
window.rootViewController = ViewController(nibName: nil, bundle: nil) window.rootViewController = ViewController()
window.makeKeyAndVisible() window.makeKeyAndVisible()
self.window = window self.window = window
return true return true

View File

@ -1,12 +0,0 @@
/* This file provided by Facebook is for non-commercial testing and evaluation
* purposes only. Facebook reserves all rights not expressly granted.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* FACEBOOK BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#import <AsyncDisplayKit/AsyncDisplayKit.h>

View File

@ -7,7 +7,7 @@
<key>CFBundleExecutable</key> <key>CFBundleExecutable</key>
<string>$(EXECUTABLE_NAME)</string> <string>$(EXECUTABLE_NAME)</string>
<key>CFBundleIdentifier</key> <key>CFBundleIdentifier</key>
<string>com.facebook.AsyncDisplayKit.$(PRODUCT_NAME:rfc1034identifier)</string> <string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
<key>CFBundleInfoDictionaryVersion</key> <key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string> <string>6.0</string>
<key>CFBundleName</key> <key>CFBundleName</key>

View File

@ -0,0 +1,53 @@
//
// TailLoadingCellNode.swift
// Sample
//
// Created by Adlai Holler on 2/1/16.
// Copyright © 2016 Facebook. All rights reserved.
//
import AsyncDisplayKit
import UIKit
final class TailLoadingCellNode: ASCellNode {
let spinner = SpinnerNode()
let text = ASTextNode()
override init() {
super.init()
addSubnode(text)
text.attributedString = NSAttributedString(
string: "Loading…",
attributes: [
NSFontAttributeName: UIFont.systemFontOfSize(12),
NSForegroundColorAttributeName: UIColor.lightGrayColor(),
NSKernAttributeName: -0.3
])
addSubnode(spinner)
}
override func layoutSpecThatFits(constrainedSize: ASSizeRange) -> ASLayoutSpec {
return ASStackLayoutSpec(
direction: .Horizontal,
spacing: 16,
justifyContent: .Center,
alignItems: .Center,
children: [ text, spinner ])
}
}
final class SpinnerNode: ASDisplayNode {
var activityIndicatorView: UIActivityIndicatorView {
return view as! UIActivityIndicatorView
}
override init() {
super.init(viewBlock: { UIActivityIndicatorView(activityIndicatorStyle: .Gray) }, didLoadBlock: nil)
preferredFrameSize.height = 32
}
override func didLoad() {
super.didLoad()
activityIndicatorView.startAnimating()
}
}

View File

@ -10,57 +10,136 @@
*/ */
import UIKit import UIKit
import AsyncDisplayKit
class ViewController: UIViewController, ASTableViewDataSource, ASTableViewDelegate { final class ViewController: ASViewController, ASTableDataSource, ASTableDelegate {
var tableView: ASTableView struct State {
var itemCount: Int
var fetchingMore: Bool
static let empty = State(itemCount: 20, fetchingMore: false)
}
enum Action {
case BeginBatchFetch
case EndBatchFetch(resultCount: Int)
}
// MARK: UIViewController. var tableNode: ASTableNode {
return node as! ASTableNode
}
override required init(nibName nibNameOrNil: String?, bundle nibBundleOrNil: NSBundle?) { private(set) var state: State = .empty
self.tableView = ASTableView()
super.init(nibName: nil, bundle: nil) init() {
super.init(node: ASTableNode())
self.tableView.asyncDataSource = self tableNode.delegate = self
self.tableView.asyncDelegate = self tableNode.dataSource = self
} }
required init?(coder aDecoder: NSCoder) { required init?(coder aDecoder: NSCoder) {
fatalError("storyboards are incompatible with truth and beauty") fatalError("storyboards are incompatible with truth and beauty")
} }
override func viewDidLoad() {
super.viewDidLoad()
self.view.addSubview(self.tableView)
}
override func viewWillLayoutSubviews() {
self.tableView.frame = self.view.bounds
}
override func prefersStatusBarHidden() -> Bool { override func prefersStatusBarHidden() -> Bool {
return true return true
} }
// MARK: ASTableView data source and delegate. // MARK: ASTableView data source and delegate.
func tableView(tableView: ASTableView!, nodeForRowAtIndexPath indexPath: NSIndexPath!) -> ASCellNode! { func tableView(tableView: ASTableView, nodeForRowAtIndexPath indexPath: NSIndexPath) -> ASCellNode {
let patter = NSString(format: "[%ld.%ld] says hello!", indexPath.section, indexPath.row) // Should read the row count directly from table view but
// https://github.com/facebook/AsyncDisplayKit/issues/1159
let rowCount = self.tableView(tableView, numberOfRowsInSection: 0)
if state.fetchingMore && indexPath.row == rowCount - 1 {
return TailLoadingCellNode()
}
let node = ASTextCellNode() let node = ASTextCellNode()
node.text = patter as String node.text = String(format: "[%ld.%ld] says hello!", indexPath.section, indexPath.row)
return node return node
} }
func numberOfSectionsInTableView(tableView: UITableView!) -> Int { func numberOfSectionsInTableView(tableView: UITableView) -> Int {
return 1 return 1
} }
func tableView(tableView: UITableView!, numberOfRowsInSection section: Int) -> Int { func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 20 var count = state.itemCount
if state.fetchingMore {
count += 1
}
return count
} }
func tableView(tableView: ASTableView, willBeginBatchFetchWithContext context: ASBatchContext) {
/// This call will come in on a background thread. Switch to main
/// to add our spinner, then fire off our fetch.
dispatch_async(dispatch_get_main_queue()) {
let oldState = self.state
self.state = ViewController.handleAction(.BeginBatchFetch, fromState: oldState)
self.renderDiff(oldState)
}
ViewController.fetchDataWithCompletion { resultCount in
let action = Action.EndBatchFetch(resultCount: resultCount)
let oldState = self.state
self.state = ViewController.handleAction(action, fromState: oldState)
self.renderDiff(oldState)
context.completeBatchFetching(true)
}
}
private func renderDiff(oldState: State) {
let tableView = tableNode.view
tableView.beginUpdates()
// Add or remove items
let rowCountChange = state.itemCount - oldState.itemCount
if rowCountChange > 0 {
let indexPaths = (oldState.itemCount..<state.itemCount).map { index in
NSIndexPath(forRow: index, inSection: 0)
}
tableView.insertRowsAtIndexPaths(indexPaths, withRowAnimation: .None)
} else if rowCountChange < 0 {
assertionFailure("Deleting rows is not implemented. YAGNI.")
}
// Add or remove spinner.
if state.fetchingMore != oldState.fetchingMore {
if state.fetchingMore {
// Add spinner.
let spinnerIndexPath = NSIndexPath(forRow: state.itemCount, inSection: 0)
tableView.insertRowsAtIndexPaths([ spinnerIndexPath ], withRowAnimation: .None)
} else {
// Remove spinner.
let spinnerIndexPath = NSIndexPath(forRow: oldState.itemCount, inSection: 0)
tableView.deleteRowsAtIndexPaths([ spinnerIndexPath ], withRowAnimation: .None)
}
}
tableView.endUpdatesAnimated(false, completion: nil)
}
/// (Pretend) fetches some new items and calls the
/// completion handler on the main thread.
private static func fetchDataWithCompletion(completion: (Int) -> Void) {
let time = dispatch_time(DISPATCH_TIME_NOW, Int64(NSTimeInterval(NSEC_PER_SEC) * 0.5))
dispatch_after(time, dispatch_get_main_queue()) {
let resultCount = Int(arc4random_uniform(20))
completion(resultCount)
}
}
private static func handleAction(action: Action, var fromState state: State) -> State {
switch action {
case .BeginBatchFetch:
state.fetchingMore = true
case let .EndBatchFetch(resultCount):
state.itemCount += resultCount
state.fetchingMore = false
}
return state
}
} }