Skip to content

Commit

Permalink
Merge pull request #18 from ra1028/lazy-target-assigning
Browse files Browse the repository at this point in the history
Lazy target assigning
  • Loading branch information
ra1028 authored May 13, 2019
2 parents ccd9019 + 65d6b80 commit 29ffa26
Show file tree
Hide file tree
Showing 51 changed files with 294 additions and 120 deletions.
4 changes: 4 additions & 0 deletions Carbon.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@
6B7ADEF421FDB12B003803BE /* UITableViewComponentHeaderFooterViewTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6B7ADEF021FDB12A003803BE /* UITableViewComponentHeaderFooterViewTests.swift */; };
6B7EED9E224CA5DD00060872 /* UIScrollViewExtensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6B7EED9D224CA5DD00060872 /* UIScrollViewExtensions.swift */; };
6B7EEDA0224CE4E100060872 /* UIScrollViewExtensionsTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6B7EED9F224CE4E000060872 /* UIScrollViewExtensionsTests.swift */; };
6BAEA3DA2289C5D10026F81E /* Deprecated.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6BAEA3D92289C5D10026F81E /* Deprecated.swift */; };
/* End PBXBuildFile section */

/* Begin PBXContainerItemProxy section */
Expand Down Expand Up @@ -122,6 +123,7 @@
6B7ADEF021FDB12A003803BE /* UITableViewComponentHeaderFooterViewTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = UITableViewComponentHeaderFooterViewTests.swift; sourceTree = "<group>"; };
6B7EED9D224CA5DD00060872 /* UIScrollViewExtensions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UIScrollViewExtensions.swift; sourceTree = "<group>"; };
6B7EED9F224CE4E000060872 /* UIScrollViewExtensionsTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UIScrollViewExtensionsTests.swift; sourceTree = "<group>"; };
6BAEA3D92289C5D10026F81E /* Deprecated.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Deprecated.swift; sourceTree = "<group>"; };
/* End PBXFileReference section */

/* Begin PBXFrameworksBuildPhase section */
Expand Down Expand Up @@ -175,6 +177,7 @@
6B65949021E2532100291AAF /* Section.swift */,
6B6594A321E2532100291AAF /* Renderer.swift */,
6B5304522201EDB200A3E21E /* DataChangeset.swift */,
6BAEA3D92289C5D10026F81E /* Deprecated.swift */,
6B65948921E2532100291AAF /* Adapters */,
6B65949221E2532100291AAF /* Updaters */,
6B65949D21E2532100291AAF /* Interfaces */,
Expand Down Expand Up @@ -439,6 +442,7 @@
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
6BAEA3DA2289C5D10026F81E /* Deprecated.swift in Sources */,
6B6594BB21E2532100291AAF /* UITableViewComponentHeaderFooterView.swift in Sources */,
6B7EED9E224CA5DD00060872 /* UIScrollViewExtensions.swift in Sources */,
6B6594AC21E2532100291AAF /* Section.swift in Sources */,
Expand Down
5 changes: 3 additions & 2 deletions Examples/Example-iOS/Sources/Emoji/EmojiViewController.swift
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,7 @@ final class EmojiViewController: UIViewController {
@IBOutlet var collectionView: UICollectionView!
@IBOutlet var toolBar: UIToolbar!

private lazy var renderer = Renderer(
target: collectionView,
private let renderer = Renderer(
adapter: UICollectionViewFlowLayoutAdapter(),
updater: UICollectionViewUpdater()
)
Expand All @@ -25,6 +24,8 @@ final class EmojiViewController: UIViewController {
title = "Shuffle Emoji"
toolBar.isTranslucent = false
collectionView.contentInset.bottom = 44

renderer.target = collectionView
renderer.updater.alwaysRenderVisibleComponents = true

refresh()
Expand Down
4 changes: 2 additions & 2 deletions Examples/Example-iOS/Sources/Form/FormViewController.swift
Original file line number Diff line number Diff line change
Expand Up @@ -36,8 +36,7 @@ final class FormViewController: UIViewController {
didSet { render() }
}

private lazy var renderer = Renderer(
target: tableView,
private let renderer = Renderer(
adapter: UITableViewAdapter(),
updater: UITableViewUpdater()
)
Expand All @@ -50,6 +49,7 @@ final class FormViewController: UIViewController {
tableView.estimatedRowHeight = UITableView.automaticDimension
NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillChangeFrame), name: UIResponder.keyboardWillChangeFrameNotification, object: nil)

renderer.target = tableView
renderer.updater.deleteRowsAnimation = .middle
renderer.updater.insertRowsAnimation = .middle
renderer.updater.insertSectionsAnimation = .top
Expand Down
4 changes: 2 additions & 2 deletions Examples/Example-iOS/Sources/Hello/HelloViewController.swift
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,7 @@ final class HelloViewController: UIViewController {
didSet { render() }
}

private lazy var renderer = Renderer(
target: tableView,
private let renderer = Renderer(
adapter: UITableViewAdapter(),
updater: UITableViewUpdater()
)
Expand All @@ -23,6 +22,7 @@ final class HelloViewController: UIViewController {

title = "Hello"
tableView.contentInset.top = 44
renderer.target = tableView

render()
}
Expand Down
4 changes: 2 additions & 2 deletions Examples/Example-iOS/Sources/Kyoto/KyotoViewController.swift
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,7 @@ final class KyotoViewController: UIViewController {

@IBOutlet var collectionView: UICollectionView!

private lazy var renderer = Renderer(
target: collectionView,
private let renderer = Renderer(
adapter: UICollectionViewFlowLayoutAdapter(),
updater: UICollectionViewUpdater()
)
Expand All @@ -21,6 +20,7 @@ final class KyotoViewController: UIViewController {
title = "Kyoto"
collectionView.contentInset.bottom = 24

renderer.target = collectionView
renderer.render(
Section(
id: ID.top,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,7 @@ final class PangramViewController: UIViewController {
@IBOutlet var collectionView: UICollectionView!
@IBOutlet var toolBar: UIToolbar!

private lazy var renderer = Renderer(
target: collectionView,
private let renderer = Renderer(
adapter: UICollectionViewFlowLayoutAdapter(),
updater: UICollectionViewUpdater()
)
Expand All @@ -21,6 +20,7 @@ final class PangramViewController: UIViewController {
title = "Pangram"
toolBar.isTranslucent = false
collectionView.contentInset.top = 44
renderer.target = collectionView

render()
}
Expand Down
5 changes: 3 additions & 2 deletions Examples/Example-iOS/Sources/Todo/TodoViewController.swift
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,7 @@ final class TodoViewController: UIViewController, UITextViewDelegate {
didSet { render() }
}

private lazy var renderer = Renderer(
target: tableView,
private let renderer = Renderer(
adapter: TodoTableViewAdapter(),
updater: UITableViewUpdater()
)
Expand All @@ -42,6 +41,8 @@ final class TodoViewController: UIViewController, UITextViewDelegate {
tableView.rowHeight = UITableView.automaticDimension
tableView.estimatedRowHeight = UITableView.automaticDimension
tableView.contentInset.bottom = view.bounds.height - addButton.frame.minY

renderer.target = tableView
renderer.updater.skipReloadComponents = true
renderer.updater.alwaysRenderVisibleComponents = true

Expand Down
4 changes: 2 additions & 2 deletions Examples/Example-iOS/Sources/Top/HomeViewController.swift
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,7 @@ final class HomeViewController: UIViewController {

@IBOutlet var tableView: UITableView!

private lazy var renderer = Renderer(
target: tableView,
private let renderer = Renderer(
adapter: UITableViewAdapter(),
updater: UITableViewUpdater()
)
Expand All @@ -28,6 +27,7 @@ final class HomeViewController: UIViewController {

title = "Home"

renderer.target = tableView
renderer.render(
Section(
id: ID.examples,
Expand Down
22 changes: 18 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -195,21 +195,31 @@ Since there are several style syntaxes for passing group of sections, please che
```swift
@IBOutlet var tableView: UITableView!

lazy var renderer = Renderer(
target: tableView,
let renderer = Renderer(
adapter: UITableViewAdapter(),
updater: UITableViewUpdater()
)

override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)

renderer.target = tableView
}
```

```swift
@IBOutlet var collectionView: UICollectionView!

lazy var renderer = Renderer(
target: collectionView,
let renderer = Renderer(
adapter: UICollectionViewFlowLayoutAdapter(),
updater: UICollectionViewUpdater()
)

override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)

renderer.target = collectionView
}
```

```swift
Expand Down Expand Up @@ -397,6 +407,10 @@ Below are some of the default provided settings of `updater`.
Indicating whether enables animation for diffing updates, setting `false` will perform it using `UIView.performWithoutAnimation`.
Default is `true`.

- **isAnimationEnabledWhileScrolling**
Indicating whether enables animation for diffing updates while target is scrolling, setting `false` will perform it using `UIView.performWithoutAnimation`.
Default is `true`.

- **animatableChangeCount**
The max number of changes to perform diffing updates. It falls back to `reloadData` if it exceeded.
Default is `300`.
Expand Down
10 changes: 10 additions & 0 deletions Sources/Deprecated.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
public extension Renderer {
/// Create a new instance with given target, adapter and updater.
/// Immediately the `prepare` of updater is called.
@available(*, deprecated, message:"Use the `Renderer.init` that accepts only `adapter` and `updater` parameters, and set `target` at arbitrary timing.")
convenience init(target: Updater.Target, adapter: Updater.Adapter, updater: Updater) {
self.init(adapter: adapter, updater: updater)
self.target = target
updater.prepare(target: target, adapter: adapter)
}
}
29 changes: 18 additions & 11 deletions Sources/Renderer.swift
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,14 @@ import UIKit
///
/// Example for render a section containing simple nodes.
///
/// let tableView: UITableView = ...
/// let renderer = Renderer(
/// target: tableView,
/// adapter: UITableViewAdapter(),
/// updater: UITableViewUpdater()
/// )
///
/// renderer.target = tableView
///
/// renderer.render(
/// Section(
/// id: "section",
Expand All @@ -27,30 +29,32 @@ import UIKit
/// )
/// )
open class Renderer<Updater: Carbon.Updater> {
/// An instance of target that weakly referenced.
public private(set) weak var target: Updater.Target?

/// An instance of adapter that specified at initialized.
public let adapter: Updater.Adapter

/// An instance of updater that specified at initialized.
public let updater: Updater

/// An instance of target that weakly referenced.
/// It will be passed to the `prepare` method of updater at didSet.
open weak var target: Updater.Target? {
didSet {
guard let target = target else { return }
updater.prepare(target: target, adapter: adapter)
}
}

/// Returns a current data held in adapter.
/// When data is set, it renders to the target immediately.
open var data: [Section] {
get { return adapter.data }
set(data) { render(data) }
}

/// Create a new instance with given target, adapter and updater.
/// Immediately the `prepare` of updater is called.
public init(target: Updater.Target, adapter: Updater.Adapter, updater: Updater) {
self.target = target
/// Create a new instance with given adapter and updater.
public init(adapter: Updater.Adapter, updater: Updater) {
self.adapter = adapter
self.updater = updater

updater.prepare(target: target, adapter: adapter)
}

/// Render given collection of sections, immediately.
Expand All @@ -59,12 +63,15 @@ open class Renderer<Updater: Carbon.Updater> {
/// - data: A collection of sections to be rendered.
/// - completion: A completion handler to be called after rendered.
open func render<C: Collection>(_ data: C, completion: (() -> Void)? = nil) where C.Element == Section {
let data = Array(data)

guard let target = target else {
adapter.data = data
completion?()
return
}

updater.performUpdates(target: target, adapter: adapter, data: Array(data), completion: completion)
updater.performUpdates(target: target, adapter: adapter, data: data, completion: completion)
}

/// Render given collection of sections after removes contained nil, immediately.
Expand Down
29 changes: 22 additions & 7 deletions Tests/RendererTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,10 @@ final class RendererTests: XCTestCase {
func testTargetWeakCapture() {
var target: MockTarget? = MockTarget()
let renderer = Renderer(
target: target!,
adapter: MockAdapter(),
updater: MockUpdater()
)
renderer.target = target

target = nil
XCTAssertNil(renderer.target)
Expand All @@ -18,24 +18,39 @@ final class RendererTests: XCTestCase {
let target = MockTarget()
let adapter = MockAdapter()
let renderer = Renderer(
target: target,
adapter: adapter,
updater: MockUpdater()
)
renderer.target = target

XCTAssertEqual(renderer.updater.targetCapturedOnPrepare, target)
XCTAssertEqual(renderer.updater.adapterCapturedOnPrepare, adapter)
}

func testRenderBeforeTargetIsSet() {
let adapter = MockAdapter()
let renderer = Renderer(
adapter: adapter,
updater: MockUpdater()
)

renderer.render(
Section(id: TestID.a),
Section(id: TestID.b)
)

XCTAssertEqual(renderer.adapter.data.count, 2)
}

func testDataSetter() {
let target = MockTarget()
let adapter = MockAdapter()
let renderer = Renderer(
target: target,
adapter: adapter,
updater: MockUpdater()
)

renderer.target = target
renderer.data = [
Section(id: TestID.a),
Section(id: TestID.b),
Expand All @@ -51,10 +66,10 @@ final class RendererTests: XCTestCase {
let target = MockTarget()
let adapter = MockAdapter()
let renderer = Renderer(
target: target,
adapter: adapter,
updater: MockUpdater()
)
renderer.target = target

var completed = false
let data = [
Expand All @@ -77,10 +92,10 @@ final class RendererTests: XCTestCase {
let target = MockTarget()
let adapter = MockAdapter()
let renderer = Renderer(
target: target,
adapter: adapter,
updater: MockUpdater()
)
renderer.target = target

var completed = false
let data = [
Expand All @@ -105,10 +120,10 @@ final class RendererTests: XCTestCase {
let target = MockTarget()
let adapter = MockAdapter()
let renderer = Renderer(
target: target,
adapter: adapter,
updater: MockUpdater()
)
renderer.target = target

var completed = false

Expand All @@ -131,10 +146,10 @@ final class RendererTests: XCTestCase {
let target = MockTarget()
let adapter = MockAdapter()
let renderer = Renderer(
target: target,
adapter: adapter,
updater: MockUpdater()
)
renderer.target = target

var completed = false

Expand Down
Loading

0 comments on commit 29ffa26

Please sign in to comment.