Skip to content

Commit

Permalink
Move onSelect/onDeselect to an async callback to give UICollectionVie…
Browse files Browse the repository at this point in the history
…w time to schedule animations. Add more signpost logging.
  • Loading branch information
kyleve committed Jun 3, 2020
1 parent 26ac904 commit dd97264
Show file tree
Hide file tree
Showing 9 changed files with 106 additions and 17 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
//

import UIKit
@testable import Listable
import Listable


final class ScrollViewEdgesPlaygroundViewController : UIViewController, UIScrollViewDelegate
Expand Down
8 changes: 8 additions & 0 deletions Demo/Sources/Demos/DemosRootViewController.swift
Original file line number Diff line number Diff line change
Expand Up @@ -143,6 +143,14 @@ public final class DemosRootViewController : UIViewController
DemoItem(text: "Tappable Row"),
selectionStyle: .tappable
)

section += Item(
DemoItem(text: "Tappable Row (Slow Is Selected)"),
selectionStyle: .tappable,
onSelect: { _ in
Thread.sleep(forTimeInterval: 0.5)
}
)
}

list += Section(identifier: "collection-view") { section in
Expand Down
5 changes: 5 additions & 0 deletions Listable/Sources/Debugging and Logging/SignpostLogger.swift
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,11 @@ extension OSLog {
subsystem: "com.kve.Listable",
category: "ListView ScrollView"
)

static let listInteraction = OSLog(
subsystem: "com.kve.Listable",
category: "ListView Interaction"
)
}


Expand Down
32 changes: 29 additions & 3 deletions Listable/Sources/Identifier.swift
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
import Foundation


public final class AnyIdentifier : Hashable
public final class AnyIdentifier : Hashable, CustomDebugStringConvertible
{
private let value : AnyHashable

Expand Down Expand Up @@ -36,13 +36,19 @@ public final class AnyIdentifier : Hashable
{
hasher.combine(self.hash)
}

// MARK: CustomDebugStringConvertible

public var debugDescription: String {
self.value.identifierContentString
}
}


public final class Identifier<Represented> : Hashable
public final class Identifier<Represented> : Hashable, CustomDebugStringConvertible
{
private let type : ObjectIdentifier
private let value : AnyHashable?
private let value : AnyHashable

private let hash : Int

Expand Down Expand Up @@ -82,4 +88,24 @@ public final class Identifier<Represented> : Hashable
{
hasher.combine(self.hash)
}

// MARK: CustomDebugStringConvertible

public var debugDescription: String {
"Identifier<\(String(describing: Represented.self))>: \(self.value.identifierContentString)"
}
}


fileprivate extension AnyHashable
{
var identifierContentString : String {
if let base = self.base as? CustomDebugStringConvertible {
return base.debugDescription
} else if let base = self.base as? CustomStringConvertible {
return base.description
} else {
return self.debugDescription
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -277,10 +277,27 @@ extension PresentationState
{
self.storage.state.isSelected = isSelected

if isSelected {
self.model.onSelect?(self.model.content)
} else {
self.model.onDeselect?(self.model.content)
/// Schedule the caller-provided callbacks to happen after one runloop. Why?
///
/// Because this method is called from within `UICollectionViewDelegate` callbacks,
/// This delay gives the `UICollectionView` time to schedule any necessary animations
/// for changes to the highlight and selection state – otherwise, these animations get
/// stuck behind the call to the `onSelect` or `onDeselect` blocks, which creates the appearance
/// of a laggy UI if these callbacks are slow.
DispatchQueue.main.async {
if isSelected {
if let onSelect = self.model.onSelect {
SignpostLogger.log(log: .listInteraction, name: "Item onSelect", for: self.model) {
onSelect(self.model.content)
}
}
} else {
if let onDeselect = self.model.onDeselect {
SignpostLogger.log(log: .listInteraction, name: "Item onDeselect", for: self.model) {
onDeselect(self.model.content)
}
}
}
}
}

Expand Down
2 changes: 1 addition & 1 deletion Listable/Sources/Item/Item.swift
Original file line number Diff line number Diff line change
Expand Up @@ -210,7 +210,7 @@ extension Item : SignpostLoggable
var signpostInfo : SignpostLoggingInfo {
SignpostLoggingInfo(
identifier: self.debuggingIdentifier,
instanceIdentifier: nil
instanceIdentifier: self.identifier.debugDescription
)
}
}
Expand Down
2 changes: 1 addition & 1 deletion Listable/Sources/ListScrollPositionInfo.swift
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,7 @@ public struct ListScrollPositionInfo : Equatable {
private let scrollViewState : ScrollViewState

/// Creates a `ListScrollPositionInfo` for the provided scroll view.
init(
public init(
scrollView : UIScrollView,
visibleItems : Set<AnyIdentifier>,
isFirstItemVisible : Bool,
Expand Down
35 changes: 34 additions & 1 deletion Listable/Tests/IdentifierTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,41 @@
//

import XCTest
import Listable

class IdentifierTests: XCTestCase

class AnyIdentifierTests: XCTestCase
{
func test_debugDescription()
{
XCTAssertEqual(
Identifier<TestingType>("The Value").toAny.debugDescription,
"Identifier<TestingType>: \"The Value\""
)

XCTAssertEqual(
Identifier<TestingType>(123).toAny.debugDescription,
"Identifier<TestingType>: 123"
)
}
}


class IdentifierTests: XCTestCase
{
func test_debugDescription()
{
XCTAssertEqual(
Identifier<TestingType>("The Value").debugDescription,
"Identifier<TestingType>: \"The Value\""
)

XCTAssertEqual(
Identifier<TestingType>(123).debugDescription,
"Identifier<TestingType>: 123"
)
}
}


fileprivate struct TestingType { }
12 changes: 6 additions & 6 deletions Podfile.lock
Original file line number Diff line number Diff line change
@@ -1,16 +1,16 @@
PODS:
- BlueprintLists (0.1.1):
- BlueprintLists (0.6.0):
- BlueprintUI
- Listable
- BlueprintLists/Tests (0.1.1):
- BlueprintLists/Tests (0.6.0):
- BlueprintUI
- Listable
- BlueprintUI (0.11.0)
- BlueprintUICommonControls (0.11.0):
- BlueprintUI
- EnglishDictionary (1.0.0.LOCAL)
- Listable (1.0.0.LOCAL)
- Listable/Tests (1.0.0.LOCAL):
- Listable (0.6.0)
- Listable/Tests (0.6.0):
- EnglishDictionary
- Snapshot
- Snapshot (1.0.0.LOCAL)
Expand Down Expand Up @@ -43,11 +43,11 @@ EXTERNAL SOURCES:
:path: Internal Pods/Snapshot/Snapshot.podspec

SPEC CHECKSUMS:
BlueprintLists: 519830595f2d2109299b599e46729cd22a0128ea
BlueprintLists: 7dde9b8cf1139be5aa5e84fb05f01a56df498c12
BlueprintUI: bc5bc9913d897c10dc44c544747afc2a63b26744
BlueprintUICommonControls: d982c07e38112d9d2d5f5d315c0edc54db0d349e
EnglishDictionary: f03968b9382ddc5c8dd63535efbf783c6cd45f1c
Listable: c4273b65906a0624b9aefce781743095ab8971f9
Listable: 836bc4b9756a96aa47e29a2e59e57386666a3288
Snapshot: cda3414db426919d09f775434b36289c8e864183

PODFILE CHECKSUM: ede5b0b1b0dfe04b49195609ea6bccb6b577e01f
Expand Down

0 comments on commit dd97264

Please sign in to comment.