mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-12-10 16:29:55 +00:00
More progress with the Swift example
This commit is contained in:
parent
67212c69b7
commit
8f10d8ea99
@ -165,28 +165,24 @@ static const NSInteger kMaxLitterSize = 100; // max number of kitten cell
|
||||
|
||||
- (void)tableView:(UITableView *)tableView willBeginBatchFetchWithContext:(ASBatchContext *)context
|
||||
{
|
||||
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
|
||||
sleep(1);
|
||||
dispatch_async(dispatch_get_main_queue(), ^{
|
||||
|
||||
// populate a new array of random-sized kittens
|
||||
NSArray *moarKittens = [self createLitterWithSize:kLitterBatchSize];
|
||||
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(1 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
|
||||
// populate a new array of random-sized kittens
|
||||
NSArray *moarKittens = [self createLitterWithSize:kLitterBatchSize];
|
||||
|
||||
NSMutableArray *indexPaths = [[NSMutableArray alloc] init];
|
||||
|
||||
// find number of kittens in the data source and create their indexPaths
|
||||
NSInteger existingRows = _kittenDataSource.count + 1;
|
||||
|
||||
for (NSInteger i = 0; i < moarKittens.count; i++) {
|
||||
[indexPaths addObject:[NSIndexPath indexPathForRow:existingRows + i inSection:0]];
|
||||
}
|
||||
NSMutableArray *indexPaths = [[NSMutableArray alloc] init];
|
||||
|
||||
// find number of kittens in the data source and create their indexPaths
|
||||
NSInteger existingRows = _kittenDataSource.count + 1;
|
||||
|
||||
for (NSInteger i = 0; i < moarKittens.count; i++) {
|
||||
[indexPaths addObject:[NSIndexPath indexPathForRow:existingRows + i inSection:0]];
|
||||
}
|
||||
|
||||
// add new kittens to the data source & notify table of new indexpaths
|
||||
[_kittenDataSource addObjectsFromArray:moarKittens];
|
||||
[tableView insertRowsAtIndexPaths:indexPaths withRowAnimation:UITableViewRowAnimationFade];
|
||||
// add new kittens to the data source & notify table of new indexpaths
|
||||
[_kittenDataSource addObjectsFromArray:moarKittens];
|
||||
[tableView insertRowsAtIndexPaths:indexPaths withRowAnimation:UITableViewRowAnimationFade];
|
||||
|
||||
[context completeBatchFetching:YES];
|
||||
});
|
||||
[context completeBatchFetching:YES];
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@ -13,6 +13,7 @@
|
||||
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 */; };
|
||||
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 */
|
||||
|
||||
/* Begin PBXFileReference section */
|
||||
@ -25,6 +26,7 @@
|
||||
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>"; };
|
||||
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>"; };
|
||||
/* End PBXFileReference section */
|
||||
|
||||
@ -64,6 +66,7 @@
|
||||
050E7C7019D22E19004363C2 /* Sample */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
CCB01CAA1C5FEA6E00CA64C4 /* TailLoadingCellNode.swift */,
|
||||
050E7C7319D22E19004363C2 /* AppDelegate.swift */,
|
||||
050E7C7519D22E19004363C2 /* ViewController.swift */,
|
||||
050E7C7119D22E19004363C2 /* Supporting Files */,
|
||||
@ -130,7 +133,7 @@
|
||||
attributes = {
|
||||
LastSwiftMigration = 0700;
|
||||
LastSwiftUpdateCheck = 0700;
|
||||
LastUpgradeCheck = 0600;
|
||||
LastUpgradeCheck = 0720;
|
||||
ORGANIZATIONNAME = Facebook;
|
||||
TargetAttributes = {
|
||||
050E7C6D19D22E19004363C2 = {
|
||||
@ -222,6 +225,7 @@
|
||||
isa = PBXSourcesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
CCB01CAB1C5FEA6E00CA64C4 /* TailLoadingCellNode.swift in Sources */,
|
||||
050E7C7619D22E19004363C2 /* ViewController.swift in Sources */,
|
||||
050E7C7419D22E19004363C2 /* AppDelegate.swift in Sources */,
|
||||
);
|
||||
@ -250,6 +254,7 @@
|
||||
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
|
||||
COPY_PHASE_STRIP = NO;
|
||||
ENABLE_STRICT_OBJC_MSGSEND = YES;
|
||||
ENABLE_TESTABILITY = YES;
|
||||
GCC_C_LANGUAGE_STANDARD = gnu99;
|
||||
GCC_DYNAMIC_NO_PIC = NO;
|
||||
GCC_OPTIMIZATION_LEVEL = 0;
|
||||
@ -314,6 +319,7 @@
|
||||
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
||||
INFOPLIST_FILE = Sample/Info.plist;
|
||||
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
|
||||
PRODUCT_BUNDLE_IDENTIFIER = "com.facebook.AsyncDisplayKit.$(PRODUCT_NAME:rfc1034identifier)";
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
};
|
||||
name = Debug;
|
||||
@ -325,6 +331,7 @@
|
||||
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
||||
INFOPLIST_FILE = Sample/Info.plist;
|
||||
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
|
||||
PRODUCT_BUNDLE_IDENTIFIER = "com.facebook.AsyncDisplayKit.$(PRODUCT_NAME:rfc1034identifier)";
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
};
|
||||
name = Release;
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<Scheme
|
||||
LastUpgradeVersion = "0620"
|
||||
LastUpgradeVersion = "0720"
|
||||
version = "1.3">
|
||||
<BuildAction
|
||||
parallelizeBuildables = "YES"
|
||||
@ -23,10 +23,10 @@
|
||||
</BuildActionEntries>
|
||||
</BuildAction>
|
||||
<TestAction
|
||||
buildConfiguration = "Debug"
|
||||
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
||||
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
||||
shouldUseLaunchSchemeArgsEnv = "YES"
|
||||
buildConfiguration = "Debug">
|
||||
shouldUseLaunchSchemeArgsEnv = "YES">
|
||||
<Testables>
|
||||
</Testables>
|
||||
<MacroExpansion>
|
||||
@ -38,15 +38,18 @@
|
||||
ReferencedContainer = "container:Sample.xcodeproj">
|
||||
</BuildableReference>
|
||||
</MacroExpansion>
|
||||
<AdditionalOptions>
|
||||
</AdditionalOptions>
|
||||
</TestAction>
|
||||
<LaunchAction
|
||||
buildConfiguration = "Debug"
|
||||
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
||||
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
||||
launchStyle = "0"
|
||||
useCustomWorkingDirectory = "NO"
|
||||
buildConfiguration = "Debug"
|
||||
ignoresPersistentStateOnLaunch = "NO"
|
||||
debugDocumentVersioning = "YES"
|
||||
debugServiceExtension = "internal"
|
||||
allowLocationSimulation = "YES">
|
||||
<BuildableProductRunnable
|
||||
runnableDebuggingMode = "0">
|
||||
@ -62,10 +65,10 @@
|
||||
</AdditionalOptions>
|
||||
</LaunchAction>
|
||||
<ProfileAction
|
||||
buildConfiguration = "Release"
|
||||
shouldUseLaunchSchemeArgsEnv = "YES"
|
||||
savedToolIdentifier = ""
|
||||
useCustomWorkingDirectory = "NO"
|
||||
buildConfiguration = "Release"
|
||||
debugDocumentVersioning = "YES">
|
||||
<BuildableProductRunnable
|
||||
runnableDebuggingMode = "0">
|
||||
|
||||
10
examples/Swift/Sample.xcworkspace/contents.xcworkspacedata
generated
Normal file
10
examples/Swift/Sample.xcworkspace/contents.xcworkspacedata
generated
Normal 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>
|
||||
@ -7,7 +7,7 @@
|
||||
<key>CFBundleExecutable</key>
|
||||
<string>$(EXECUTABLE_NAME)</string>
|
||||
<key>CFBundleIdentifier</key>
|
||||
<string>com.facebook.AsyncDisplayKit.$(PRODUCT_NAME:rfc1034identifier)</string>
|
||||
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
|
||||
<key>CFBundleInfoDictionaryVersion</key>
|
||||
<string>6.0</string>
|
||||
<key>CFBundleName</key>
|
||||
|
||||
53
examples/Swift/Sample/TailLoadingCellNode.swift
Normal file
53
examples/Swift/Sample/TailLoadingCellNode.swift
Normal 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()
|
||||
}
|
||||
}
|
||||
@ -14,10 +14,23 @@ import AsyncDisplayKit
|
||||
|
||||
final class ViewController: ASViewController, ASTableDataSource, ASTableDelegate {
|
||||
|
||||
struct State {
|
||||
var rowCount: Int
|
||||
var showingSpinner: Bool
|
||||
static let empty = State(rowCount: 20, showingSpinner: false)
|
||||
}
|
||||
|
||||
enum Action {
|
||||
case BeginBatchFetch
|
||||
case EndBatchFetch(resultCount: Int)
|
||||
}
|
||||
|
||||
var tableNode: ASTableNode {
|
||||
return node as! ASTableNode
|
||||
}
|
||||
|
||||
private(set) var state: State = .empty
|
||||
|
||||
init() {
|
||||
super.init(node: ASTableNode())
|
||||
tableNode.delegate = self
|
||||
@ -35,6 +48,11 @@ final class ViewController: ASViewController, ASTableDataSource, ASTableDelegate
|
||||
// MARK: ASTableView data source and delegate.
|
||||
|
||||
func tableView(tableView: ASTableView, nodeForRowAtIndexPath indexPath: NSIndexPath) -> ASCellNode {
|
||||
NSLog("Number of rows %d", tableView.numberOfRowsInSection(0))
|
||||
if state.showingSpinner && indexPath.row == tableView.numberOfRowsInSection(0) - 1 {
|
||||
return TailLoadingCellNode()
|
||||
}
|
||||
|
||||
let node = ASTextCellNode()
|
||||
node.text = String(format: "[%ld.%ld] says hello!", indexPath.section, indexPath.row)
|
||||
|
||||
@ -46,7 +64,70 @@ final class ViewController: ASViewController, ASTableDataSource, ASTableDelegate
|
||||
}
|
||||
|
||||
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
|
||||
return 20
|
||||
var count = state.rowCount
|
||||
if state.showingSpinner {
|
||||
count += 1
|
||||
}
|
||||
return count
|
||||
}
|
||||
|
||||
func tableView(tableView: ASTableView, willBeginBatchFetchWithContext context: ASBatchContext) {
|
||||
context.cancelBatchFetching()
|
||||
dispatch_async(dispatch_get_main_queue()) {
|
||||
let oldState = self.state
|
||||
self.state = ViewController.handleAction(.BeginBatchFetch, fromState: oldState)
|
||||
self.render(oldState)
|
||||
}
|
||||
return;
|
||||
|
||||
let time = dispatch_time(DISPATCH_TIME_NOW, Int64(NSTimeInterval(NSEC_PER_SEC) * 3))
|
||||
dispatch_after(time, dispatch_get_main_queue()) {
|
||||
let action = Action.EndBatchFetch(resultCount: 20)
|
||||
let oldState = self.state
|
||||
self.state = ViewController.handleAction(action, fromState: oldState)
|
||||
self.render(oldState)
|
||||
context.completeBatchFetching(true)
|
||||
}
|
||||
}
|
||||
|
||||
func render(oldState: State) {
|
||||
let tableView = tableNode.view
|
||||
tableView.beginUpdates()
|
||||
|
||||
// Add or remove items
|
||||
let rowCountChange = state.rowCount - oldState.rowCount
|
||||
if rowCountChange > 0 {
|
||||
let indexPaths = (oldState.rowCount..<state.rowCount).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.showingSpinner && !oldState.showingSpinner {
|
||||
if state.showingSpinner {
|
||||
// Add spinner.
|
||||
let spinnerIndexPath = NSIndexPath(forRow: state.rowCount, inSection: 0)
|
||||
tableView.insertRowsAtIndexPaths([ spinnerIndexPath ], withRowAnimation: .None)
|
||||
} else {
|
||||
// Remove spinner.
|
||||
let spinnerIndexPath = NSIndexPath(forRow: oldState.rowCount, inSection: 0)
|
||||
tableView.deleteRowsAtIndexPaths([ spinnerIndexPath ], withRowAnimation: .None)
|
||||
}
|
||||
}
|
||||
tableView.endUpdatesAnimated(false, completion: nil)
|
||||
}
|
||||
|
||||
static func handleAction(action: Action, var fromState state: State) -> State {
|
||||
switch action {
|
||||
case .BeginBatchFetch:
|
||||
state.showingSpinner = true
|
||||
case let .EndBatchFetch(resultCount):
|
||||
state.rowCount += resultCount
|
||||
state.showingSpinner = false
|
||||
}
|
||||
return state
|
||||
}
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user