Skip to content

Commit 6d08e7d

Browse files
committed
update readme
1 parent 6c83355 commit 6d08e7d

File tree

3 files changed

+169
-1
lines changed

3 files changed

+169
-1
lines changed

ArkDemo/HomeFeed.swift

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,6 @@
88

99
import Foundation
1010
import Ark
11-
import AsyncDisplayKit
1211

1312
enum HomeFeed: SectionInflator {
1413

Assets/Ark.png

125 KB
Loading

README.md

Lines changed: 169 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,171 @@
11
# Ark
22

3+
**Ark** provides an option to adopt high performance of both **Texture** and **IGListKit**, without any boilerplate code stand in the way.
4+
5+
## Internal Workflow
6+
![Ark](Assets/Ark.png)
7+
8+
1. an instance of `A` which implements **SectionInflator** protocol.
9+
2. applying a new snapshot triggers diff processing.
10+
3. instance of `ASCollectionNode` from _Texture_.
11+
4. call `performBatchUpdates` on *collectionNode* with diff results.
12+
5. instance of **SectionInflator** provides an array of **AnyNodable** elements.
13+
6. instance of **AnyNodable** will map to an instance of `ASCellNode` in *collectionNode*.
14+
7. *collectionNode*'s delegate methods create a new event passed into **rx.nodeEventChannel**.
15+
8. showing an example what a custom cell node looks like.
16+
9. custom node maps user action to an event in **rx.nodeEventChannel**.
17+
10. differentiate user actions by enum `NodeEvent.Action`.
18+
11. subscribe to **rx.nodeEventChannel** on instance of **DiffableDataSource** for future events (more details later).
19+
20+
## Transition to Ark
21+
22+
### Prerequisite
23+
1. [Texture](https://github.com/texturegroup/texture), especially [_LayoutSpecs_](https://texturegroup.org/docs/layout2-layoutspec-types.html).
24+
2. [RxSwift](https://github.com/ReactiveX/RxSwift)
25+
26+
### Setup
27+
1. Set `ASCollectionNode` as ViewController's _root_ node.
28+
29+
```swift
30+
import AsyncDisplayKit
31+
32+
class ViewController: ASDKViewController<ASCollectionNode> {
33+
required init?(coder: NSCoder) { // storyboard
34+
// create layout instance
35+
let node = ASCollectionNode(collectionViewLayout: layout)
36+
super.init(node)
37+
}
38+
}
39+
```
40+
41+
2. Create an instance of `DiffableDataSource`.
42+
43+
```swift
44+
import Ark
45+
46+
class ViewController: ASDKViewController<ASCollectionNode> {
47+
private lazy var dataSource = DiffableDataSource<HomeFeed>(collectionNode: node)
48+
49+
// ...
50+
}
51+
```
52+
53+
3. Implements `SectionInflator` for your _HomeFeed_ type.
54+
55+
```swift
56+
import Ark
57+
58+
enum HomeFeed: SectionInflator {
59+
case banner(Banner)[^]
60+
case subjects(SubjectFeed)
61+
62+
var diffIdentifier: AnyHashbale {
63+
switch self {
64+
case .banner(let banner):
65+
return banner.diffIdentifier
66+
case .subjects(let feed):
67+
return feed.date
68+
}
69+
}
70+
71+
var items: [AnyNodable] {
72+
switch self {
73+
case .banner(let banner):
74+
return [AnyNodable(banner)]
75+
case .subjects(let feed):
76+
return feed.subjects.map(AnyNodable.init)
77+
}
78+
}
79+
}
80+
```
81+
82+
4. Implements `Nodable` for your _Banner_ type.
83+
84+
```swift
85+
struct Banner: Nodable {
86+
let imageName: String
87+
88+
var diffIdentifier: AnyHashable {
89+
imageName
90+
}
91+
92+
func nodeBlock(with channel: NodeEventChannel, indexPath: IndexPath) -> ASCellNodeBlock {
93+
let image = UIImage(named: imageName)! // main thread operation
94+
return { Node(image: image) }
95+
}
96+
97+
final class Node: ASCellNode {
98+
var imageNode: ASImageNode
99+
100+
init(image: UIImage) {
101+
self.imageNode = ASImageNode()
102+
103+
super.init()
104+
105+
automaticallyManagesSubnodes = true
106+
backgroundColor = .systemBackground
107+
108+
imageNode.image = image
109+
imageNode.cornerRadius = 4
110+
imageNode.contentMode = .scaleAspectFit
111+
}
112+
113+
override func layoutSpecThatFits(_ constrainedSize: ASSizeRange) -> ASLayoutSpec {
114+
ASWrapperLayoutSpec(layoutElement: imageNode)
115+
}
116+
}
117+
}
118+
```
119+
120+
5. Subscribe on `rx.nodeEventChannel` of `dataSource` to handle collection node's delegate methods callback and other target actions, for example, to move the selected subject to the bottom of the section:
121+
122+
```swift
123+
dataSource
124+
.rx.nodeEventChannel()
125+
.subscribe(onNext: { [unowned self] (event: GenericNodeEvent<SubjectFeed.Subject>) in
126+
let targetSection = event.indexPath.section
127+
guard case .subjects(let feed) = self.sections[targetSection],
128+
let index = feed.subjects.firstIndex(of: event.model) else {
129+
return
130+
}
131+
if case .selected = event.action {
132+
var subjects = feed.subjects
133+
subjects.remove(at: index)
134+
subjects.append(event.model)
135+
let newFeed: HomeFeed = .subjects(.init(date: feed.date, subjects: subjects))
136+
self.sections[targetSection] = newFeed
137+
}
138+
})
139+
.disposed(by: disposeBag)
140+
```
141+
Note that in `onNext` closure you should specify the `Nodable` type, and it will be called when events related to or from that type's node arrives.
142+
143+
6. Call `apply(_:animatingDifferences:completion:)` on `dataSource`, Isn't this what you have been waiting for?
144+
145+
```swift
146+
private var sections: [HomeFeed] = [] {
147+
didSet {
148+
updateUI(animated: true)
149+
}
150+
}
151+
152+
private fun updateUI(animated: Bool = false) {
153+
dataSource.apply(.init(sections: sections), animatingDifferences: true, completion: nil)
154+
}
155+
```
156+
157+
## TODO:
158+
159+
- [ ] Support Installation via CocoaPods
160+
161+
## References
162+
+ [ListDiff: Swift port of IGListKit's IGListDiff](https://github.com/lxcid/ListDiff)
163+
164+
## Index
165+
+ [DiffableDataSource](https://github.com/imkdir/Ark/blob/master/Ark/DiffableDataSource.swift#L45)
166+
+ [DiffableDataSourceSnapshot](https://github.com/imkdir/Ark/blob/6c83355663b9c0c9eadbd2b84512e3528d5ac981/Ark/DiffableDataSource.swift#L15)
167+
+ [NodeEventChannel](https://github.com/imkdir/Ark/blob/6c83355663b9c0c9eadbd2b84512e3528d5ac981/Ark/DiffableDataSource.swift#L34)
168+
+ [SectionInflator](https://github.com/imkdir/Ark/blob/6c83355663b9c0c9eadbd2b84512e3528d5ac981/Ark/Nodable.swift#L17)
169+
+ [Nodable](https://github.com/imkdir/Ark/blob/6c83355663b9c0c9eadbd2b84512e3528d5ac981/Ark/Nodable.swift#L24)
170+
+ [AnyNodable](https://github.com/imkdir/Ark/blob/master/Ark/AnyNodable.swift#L84)
171+
+ [GenericNodeEvent](https://github.com/imkdir/Ark/blob/6c83355663b9c0c9eadbd2b84512e3528d5ac981/Ark/NodeEvent.swift#L33)

0 commit comments

Comments
 (0)