From 51741a7cac61fc70c43d336278fefa8b007c24ac Mon Sep 17 00:00:00 2001 From: Christoffer Winterkvist Date: Tue, 5 Nov 2019 18:00:26 +0100 Subject: [PATCH 1/7] Add safe-guard for reloading without a superview Fixes crash where the view has yet to get a superview. Instead of running the `performBatchUpdates`, the implementation will now invoke `updateDataSource` and run the completion. --- Differific.podspec | 2 +- Source/iOS+tvOS/UICollectionView+Extensions.swift | 3 ++- Source/iOS+tvOS/UITableView+Extensions.swift | 3 ++- Source/macOS/NSCollectionView+Extensions.swift | 3 ++- Source/macOS/NSTableView+Extensions.swift | 3 ++- 5 files changed, 9 insertions(+), 5 deletions(-) diff --git a/Differific.podspec b/Differific.podspec index 7d6ec97..d2a3a66 100644 --- a/Differific.podspec +++ b/Differific.podspec @@ -1,7 +1,7 @@ Pod::Spec.new do |s| s.name = "Differific" s.summary = "A fast and convenient diffing framework" - s.version = "0.8.2" + s.version = "0.8.3" s.homepage = "https://github.com/zenangst/Differific" s.license = 'MIT' s.author = { "Christoffer Winterkvist" => "christoffer@winterkvist.com" } diff --git a/Source/iOS+tvOS/UICollectionView+Extensions.swift b/Source/iOS+tvOS/UICollectionView+Extensions.swift index f6e2bba..4f9d715 100644 --- a/Source/iOS+tvOS/UICollectionView+Extensions.swift +++ b/Source/iOS+tvOS/UICollectionView+Extensions.swift @@ -13,7 +13,8 @@ extension UICollectionView { section: Int = 0, updateDataSource: (() -> Void), completion: (() -> Void)? = nil) { - guard !changes.isEmpty else { + guard !changes.isEmpty && (superview != nil) else { + updateDataSource() completion?() return } diff --git a/Source/iOS+tvOS/UITableView+Extensions.swift b/Source/iOS+tvOS/UITableView+Extensions.swift index 14289c6..1030735 100644 --- a/Source/iOS+tvOS/UITableView+Extensions.swift +++ b/Source/iOS+tvOS/UITableView+Extensions.swift @@ -15,7 +15,8 @@ public extension UITableView { section: Int = 0, updateDataSource: (() -> Void), completion: (() -> Void)? = nil) { - guard !changes.isEmpty else { + guard !changes.isEmpty && (superview != nil) else { + updateDataSource() completion?() return } diff --git a/Source/macOS/NSCollectionView+Extensions.swift b/Source/macOS/NSCollectionView+Extensions.swift index 98e6f58..fd3ecbc 100644 --- a/Source/macOS/NSCollectionView+Extensions.swift +++ b/Source/macOS/NSCollectionView+Extensions.swift @@ -14,7 +14,8 @@ public extension NSCollectionView { section: Int = 0, updateDataSource: (() -> Void), completion: (() -> Void)? = nil) { - guard !changes.isEmpty else { + guard !changes.isEmpty && (superview != nil) else { + updateDataSource() completion?() return } diff --git a/Source/macOS/NSTableView+Extensions.swift b/Source/macOS/NSTableView+Extensions.swift index 95ba3d9..9f235e6 100644 --- a/Source/macOS/NSTableView+Extensions.swift +++ b/Source/macOS/NSTableView+Extensions.swift @@ -15,7 +15,8 @@ public extension NSTableView { section: Int = 0, updateDataSource: (() -> Void), completion: (() -> Void)? = nil) { - guard !changes.isEmpty else { + guard !changes.isEmpty && !(superview != nil) else { + updateDataSource() completion?() return } From b365fcd02620b1ca76ab3df5b2b2adc9bbf61ccd Mon Sep 17 00:00:00 2001 From: Christoffer Winterkvist Date: Tue, 5 Nov 2019 18:06:25 +0100 Subject: [PATCH 2/7] Remove calling updateDataSource() --- Source/iOS+tvOS/UICollectionView+Extensions.swift | 1 - Source/iOS+tvOS/UITableView+Extensions.swift | 1 - Source/macOS/NSCollectionView+Extensions.swift | 1 - Source/macOS/NSTableView+Extensions.swift | 1 - 4 files changed, 4 deletions(-) diff --git a/Source/iOS+tvOS/UICollectionView+Extensions.swift b/Source/iOS+tvOS/UICollectionView+Extensions.swift index 4f9d715..850a022 100644 --- a/Source/iOS+tvOS/UICollectionView+Extensions.swift +++ b/Source/iOS+tvOS/UICollectionView+Extensions.swift @@ -14,7 +14,6 @@ extension UICollectionView { updateDataSource: (() -> Void), completion: (() -> Void)? = nil) { guard !changes.isEmpty && (superview != nil) else { - updateDataSource() completion?() return } diff --git a/Source/iOS+tvOS/UITableView+Extensions.swift b/Source/iOS+tvOS/UITableView+Extensions.swift index 1030735..9bf0271 100644 --- a/Source/iOS+tvOS/UITableView+Extensions.swift +++ b/Source/iOS+tvOS/UITableView+Extensions.swift @@ -16,7 +16,6 @@ public extension UITableView { updateDataSource: (() -> Void), completion: (() -> Void)? = nil) { guard !changes.isEmpty && (superview != nil) else { - updateDataSource() completion?() return } diff --git a/Source/macOS/NSCollectionView+Extensions.swift b/Source/macOS/NSCollectionView+Extensions.swift index fd3ecbc..422cc37 100644 --- a/Source/macOS/NSCollectionView+Extensions.swift +++ b/Source/macOS/NSCollectionView+Extensions.swift @@ -15,7 +15,6 @@ public extension NSCollectionView { updateDataSource: (() -> Void), completion: (() -> Void)? = nil) { guard !changes.isEmpty && (superview != nil) else { - updateDataSource() completion?() return } diff --git a/Source/macOS/NSTableView+Extensions.swift b/Source/macOS/NSTableView+Extensions.swift index 9f235e6..9a11655 100644 --- a/Source/macOS/NSTableView+Extensions.swift +++ b/Source/macOS/NSTableView+Extensions.swift @@ -16,7 +16,6 @@ public extension NSTableView { updateDataSource: (() -> Void), completion: (() -> Void)? = nil) { guard !changes.isEmpty && !(superview != nil) else { - updateDataSource() completion?() return } From f4bbb7c12c20e5b65b29f8be297bb8f08f5f6d2c Mon Sep 17 00:00:00 2001 From: Christoffer Winterkvist Date: Tue, 5 Nov 2019 18:10:42 +0100 Subject: [PATCH 3/7] Call updateDataSource() --- Source/iOS+tvOS/UICollectionView+Extensions.swift | 1 + Source/iOS+tvOS/UITableView+Extensions.swift | 1 + Source/macOS/NSCollectionView+Extensions.swift | 1 + Source/macOS/NSTableView+Extensions.swift | 1 + Tests/macOS/NSCollectionViewExtensionTests.swift | 4 ++++ 5 files changed, 8 insertions(+) diff --git a/Source/iOS+tvOS/UICollectionView+Extensions.swift b/Source/iOS+tvOS/UICollectionView+Extensions.swift index 850a022..4f9d715 100644 --- a/Source/iOS+tvOS/UICollectionView+Extensions.swift +++ b/Source/iOS+tvOS/UICollectionView+Extensions.swift @@ -14,6 +14,7 @@ extension UICollectionView { updateDataSource: (() -> Void), completion: (() -> Void)? = nil) { guard !changes.isEmpty && (superview != nil) else { + updateDataSource() completion?() return } diff --git a/Source/iOS+tvOS/UITableView+Extensions.swift b/Source/iOS+tvOS/UITableView+Extensions.swift index 9bf0271..1030735 100644 --- a/Source/iOS+tvOS/UITableView+Extensions.swift +++ b/Source/iOS+tvOS/UITableView+Extensions.swift @@ -16,6 +16,7 @@ public extension UITableView { updateDataSource: (() -> Void), completion: (() -> Void)? = nil) { guard !changes.isEmpty && (superview != nil) else { + updateDataSource() completion?() return } diff --git a/Source/macOS/NSCollectionView+Extensions.swift b/Source/macOS/NSCollectionView+Extensions.swift index 422cc37..fd3ecbc 100644 --- a/Source/macOS/NSCollectionView+Extensions.swift +++ b/Source/macOS/NSCollectionView+Extensions.swift @@ -15,6 +15,7 @@ public extension NSCollectionView { updateDataSource: (() -> Void), completion: (() -> Void)? = nil) { guard !changes.isEmpty && (superview != nil) else { + updateDataSource() completion?() return } diff --git a/Source/macOS/NSTableView+Extensions.swift b/Source/macOS/NSTableView+Extensions.swift index 9a11655..9f235e6 100644 --- a/Source/macOS/NSTableView+Extensions.swift +++ b/Source/macOS/NSTableView+Extensions.swift @@ -16,6 +16,7 @@ public extension NSTableView { updateDataSource: (() -> Void), completion: (() -> Void)? = nil) { guard !changes.isEmpty && !(superview != nil) else { + updateDataSource() completion?() return } diff --git a/Tests/macOS/NSCollectionViewExtensionTests.swift b/Tests/macOS/NSCollectionViewExtensionTests.swift index 27211c6..01e5f85 100644 --- a/Tests/macOS/NSCollectionViewExtensionTests.swift +++ b/Tests/macOS/NSCollectionViewExtensionTests.swift @@ -50,7 +50,9 @@ class NSCollectionViewExtensionsTests: XCTestCase { let dataSource = DataSourceMock(models: ["Foo", "Bar", "Baz"]) let layout = NSCollectionViewFlowLayout() layout.itemSize = CGSize(width: 250, height: 250) + let superview = NSView() let collectionView = NSCollectionView(frame: .init(origin: .zero, size: layout.itemSize)) + superview.addSubview(collectionView) collectionView.collectionViewLayout = layout collectionView.dataSource = dataSource collectionView.register(NSCollectionViewItem.self, forItemWithIdentifier: NSUserInterfaceItemIdentifier.init("cell")) @@ -78,7 +80,9 @@ class NSCollectionViewExtensionsTests: XCTestCase { let dataSource = DataSourceMock(models: ["Foo", "Bar", "Baz"]) let layout = NSCollectionViewFlowLayout() layout.itemSize = CGSize(width: 250, height: 250) + let superview = NSView() let collectionView = NSCollectionView(frame: .init(origin: .zero, size: layout.itemSize)) + superview.addSubview(collectionView) collectionView.collectionViewLayout = layout collectionView.dataSource = dataSource collectionView.register(NSCollectionViewItem.self, forItemWithIdentifier: NSUserInterfaceItemIdentifier.init("cell")) From 02fa93cec7282447628e2a505ca76c86766ae9c5 Mon Sep 17 00:00:00 2001 From: Christoffer Winterkvist Date: Tue, 5 Nov 2019 18:11:24 +0100 Subject: [PATCH 4/7] Update tests --- Tests/iOS+tvOS/UICollectionViewExtensionsTests.swift | 2 +- Tests/iOS+tvOS/UITableViewExtensionsTests.swift | 2 +- Tests/macOS/NSCollectionViewExtensionTests.swift | 2 +- Tests/macOS/NSTableViewExtensionsTests.swift | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Tests/iOS+tvOS/UICollectionViewExtensionsTests.swift b/Tests/iOS+tvOS/UICollectionViewExtensionsTests.swift index 27e2b09..2244a40 100644 --- a/Tests/iOS+tvOS/UICollectionViewExtensionsTests.swift +++ b/Tests/iOS+tvOS/UICollectionViewExtensionsTests.swift @@ -126,7 +126,7 @@ class UICollectionViewExtensionsTests: XCTestCase { ranCompletion = true } - XCTAssertFalse(ranBefore) + XCTAssertTrue(ranBefore) XCTAssertTrue(ranCompletion) } } diff --git a/Tests/iOS+tvOS/UITableViewExtensionsTests.swift b/Tests/iOS+tvOS/UITableViewExtensionsTests.swift index eb110d8..5fa983c 100644 --- a/Tests/iOS+tvOS/UITableViewExtensionsTests.swift +++ b/Tests/iOS+tvOS/UITableViewExtensionsTests.swift @@ -119,7 +119,7 @@ class UITableViewExtensionsTests: XCTestCase { ranCompletion = true } - XCTAssertFalse(ranBefore) + XCTAssertTrue(ranBefore) XCTAssertTrue(ranCompletion) } } diff --git a/Tests/macOS/NSCollectionViewExtensionTests.swift b/Tests/macOS/NSCollectionViewExtensionTests.swift index 01e5f85..b20c115 100644 --- a/Tests/macOS/NSCollectionViewExtensionTests.swift +++ b/Tests/macOS/NSCollectionViewExtensionTests.swift @@ -130,7 +130,7 @@ class NSCollectionViewExtensionsTests: XCTestCase { ranCompletion = true } - XCTAssertFalse(ranBefore) + XCTAssertTrue(ranBefore) XCTAssertTrue(ranCompletion) } } diff --git a/Tests/macOS/NSTableViewExtensionsTests.swift b/Tests/macOS/NSTableViewExtensionsTests.swift index 540def4..baf0ac5 100644 --- a/Tests/macOS/NSTableViewExtensionsTests.swift +++ b/Tests/macOS/NSTableViewExtensionsTests.swift @@ -106,7 +106,7 @@ class NSTableViewExtensionsTests: XCTestCase { ranCompletion = true } - XCTAssertFalse(ranBefore) + XCTAssertTrue(ranBefore) XCTAssertTrue(ranCompletion) } } From dee04ca85bfd0cd12d3ac459d165ba93e77ced14 Mon Sep 17 00:00:00 2001 From: Christoffer Winterkvist Date: Tue, 5 Nov 2019 18:20:23 +0100 Subject: [PATCH 5/7] Split safe-guards Use `reloadData` if there is no `superview` --- Source/iOS+tvOS/UICollectionView+Extensions.swift | 9 +++++++-- Source/iOS+tvOS/UITableView+Extensions.swift | 9 +++++++-- Source/macOS/NSCollectionView+Extensions.swift | 9 +++++++-- Source/macOS/NSTableView+Extensions.swift | 9 +++++++-- 4 files changed, 28 insertions(+), 8 deletions(-) diff --git a/Source/iOS+tvOS/UICollectionView+Extensions.swift b/Source/iOS+tvOS/UICollectionView+Extensions.swift index 4f9d715..5aca864 100644 --- a/Source/iOS+tvOS/UICollectionView+Extensions.swift +++ b/Source/iOS+tvOS/UICollectionView+Extensions.swift @@ -13,12 +13,17 @@ extension UICollectionView { section: Int = 0, updateDataSource: (() -> Void), completion: (() -> Void)? = nil) { - guard !changes.isEmpty && (superview != nil) else { - updateDataSource() + guard !changes.isEmpty else { completion?() return } + if superview == nil { + updateDataSource() + reloadData() + return + } + setNeedsLayout() layoutIfNeeded() diff --git a/Source/iOS+tvOS/UITableView+Extensions.swift b/Source/iOS+tvOS/UITableView+Extensions.swift index 1030735..6781872 100644 --- a/Source/iOS+tvOS/UITableView+Extensions.swift +++ b/Source/iOS+tvOS/UITableView+Extensions.swift @@ -15,12 +15,17 @@ public extension UITableView { section: Int = 0, updateDataSource: (() -> Void), completion: (() -> Void)? = nil) { - guard !changes.isEmpty && (superview != nil) else { - updateDataSource() + guard !changes.isEmpty else { completion?() return } + if superview == nil { + updateDataSource() + reloadData() + return + } + setNeedsLayout() layoutIfNeeded() diff --git a/Source/macOS/NSCollectionView+Extensions.swift b/Source/macOS/NSCollectionView+Extensions.swift index fd3ecbc..3710ca1 100644 --- a/Source/macOS/NSCollectionView+Extensions.swift +++ b/Source/macOS/NSCollectionView+Extensions.swift @@ -14,12 +14,17 @@ public extension NSCollectionView { section: Int = 0, updateDataSource: (() -> Void), completion: (() -> Void)? = nil) { - guard !changes.isEmpty && (superview != nil) else { - updateDataSource() + guard !changes.isEmpty else { completion?() return } + if superview == nil { + updateDataSource() + reloadData() + return + } + let manager = IndexPathManager() let result = manager.process(changes, section: section) let object = animations ? animator() : self diff --git a/Source/macOS/NSTableView+Extensions.swift b/Source/macOS/NSTableView+Extensions.swift index 9f235e6..c56dcde 100644 --- a/Source/macOS/NSTableView+Extensions.swift +++ b/Source/macOS/NSTableView+Extensions.swift @@ -15,11 +15,16 @@ public extension NSTableView { section: Int = 0, updateDataSource: (() -> Void), completion: (() -> Void)? = nil) { - guard !changes.isEmpty && !(superview != nil) else { - updateDataSource() + guard !changes.isEmpty else { completion?() return } + + if superview == nil { + updateDataSource() + reloadData() + return + } let manager = IndexPathManager() let result = manager.process(changes, section: section) From f79975afd2918d11c2dd180be61c204596d5ab2d Mon Sep 17 00:00:00 2001 From: Christoffer Winterkvist Date: Tue, 5 Nov 2019 18:26:17 +0100 Subject: [PATCH 6/7] Call completion --- Source/iOS+tvOS/UICollectionView+Extensions.swift | 1 + Source/iOS+tvOS/UITableView+Extensions.swift | 1 + Source/macOS/NSCollectionView+Extensions.swift | 1 + Source/macOS/NSTableView+Extensions.swift | 1 + 4 files changed, 4 insertions(+) diff --git a/Source/iOS+tvOS/UICollectionView+Extensions.swift b/Source/iOS+tvOS/UICollectionView+Extensions.swift index 5aca864..0bcb1ec 100644 --- a/Source/iOS+tvOS/UICollectionView+Extensions.swift +++ b/Source/iOS+tvOS/UICollectionView+Extensions.swift @@ -21,6 +21,7 @@ extension UICollectionView { if superview == nil { updateDataSource() reloadData() + completion?() return } diff --git a/Source/iOS+tvOS/UITableView+Extensions.swift b/Source/iOS+tvOS/UITableView+Extensions.swift index 6781872..2c4afea 100644 --- a/Source/iOS+tvOS/UITableView+Extensions.swift +++ b/Source/iOS+tvOS/UITableView+Extensions.swift @@ -23,6 +23,7 @@ public extension UITableView { if superview == nil { updateDataSource() reloadData() + completion?() return } diff --git a/Source/macOS/NSCollectionView+Extensions.swift b/Source/macOS/NSCollectionView+Extensions.swift index 3710ca1..8e2306f 100644 --- a/Source/macOS/NSCollectionView+Extensions.swift +++ b/Source/macOS/NSCollectionView+Extensions.swift @@ -22,6 +22,7 @@ public extension NSCollectionView { if superview == nil { updateDataSource() reloadData() + completion?() return } diff --git a/Source/macOS/NSTableView+Extensions.swift b/Source/macOS/NSTableView+Extensions.swift index c56dcde..8d8d4e5 100644 --- a/Source/macOS/NSTableView+Extensions.swift +++ b/Source/macOS/NSTableView+Extensions.swift @@ -23,6 +23,7 @@ public extension NSTableView { if superview == nil { updateDataSource() reloadData() + completion?() return } From fa251ba19adbe4d55834016b0e0fd26e3a52b29c Mon Sep 17 00:00:00 2001 From: Christoffer Winterkvist Date: Tue, 5 Nov 2019 18:27:24 +0100 Subject: [PATCH 7/7] Update tests --- Tests/iOS+tvOS/UICollectionViewExtensionsTests.swift | 2 +- Tests/iOS+tvOS/UITableViewExtensionsTests.swift | 2 +- Tests/macOS/NSCollectionViewExtensionTests.swift | 2 +- Tests/macOS/NSTableViewExtensionsTests.swift | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Tests/iOS+tvOS/UICollectionViewExtensionsTests.swift b/Tests/iOS+tvOS/UICollectionViewExtensionsTests.swift index 2244a40..27e2b09 100644 --- a/Tests/iOS+tvOS/UICollectionViewExtensionsTests.swift +++ b/Tests/iOS+tvOS/UICollectionViewExtensionsTests.swift @@ -126,7 +126,7 @@ class UICollectionViewExtensionsTests: XCTestCase { ranCompletion = true } - XCTAssertTrue(ranBefore) + XCTAssertFalse(ranBefore) XCTAssertTrue(ranCompletion) } } diff --git a/Tests/iOS+tvOS/UITableViewExtensionsTests.swift b/Tests/iOS+tvOS/UITableViewExtensionsTests.swift index 5fa983c..eb110d8 100644 --- a/Tests/iOS+tvOS/UITableViewExtensionsTests.swift +++ b/Tests/iOS+tvOS/UITableViewExtensionsTests.swift @@ -119,7 +119,7 @@ class UITableViewExtensionsTests: XCTestCase { ranCompletion = true } - XCTAssertTrue(ranBefore) + XCTAssertFalse(ranBefore) XCTAssertTrue(ranCompletion) } } diff --git a/Tests/macOS/NSCollectionViewExtensionTests.swift b/Tests/macOS/NSCollectionViewExtensionTests.swift index b20c115..01e5f85 100644 --- a/Tests/macOS/NSCollectionViewExtensionTests.swift +++ b/Tests/macOS/NSCollectionViewExtensionTests.swift @@ -130,7 +130,7 @@ class NSCollectionViewExtensionsTests: XCTestCase { ranCompletion = true } - XCTAssertTrue(ranBefore) + XCTAssertFalse(ranBefore) XCTAssertTrue(ranCompletion) } } diff --git a/Tests/macOS/NSTableViewExtensionsTests.swift b/Tests/macOS/NSTableViewExtensionsTests.swift index baf0ac5..540def4 100644 --- a/Tests/macOS/NSTableViewExtensionsTests.swift +++ b/Tests/macOS/NSTableViewExtensionsTests.swift @@ -106,7 +106,7 @@ class NSTableViewExtensionsTests: XCTestCase { ranCompletion = true } - XCTAssertTrue(ranBefore) + XCTAssertFalse(ranBefore) XCTAssertTrue(ranCompletion) } }