Skip to content

Commit 68ef17c

Browse files
authored
[V5] Remove controllerWillChangeChannels and cleanup willChange handling (#3826)
1 parent 5fd4972 commit 68ef17c

File tree

8 files changed

+6
-114
lines changed

8 files changed

+6
-114
lines changed

Sources/StreamChat/Controllers/ChannelListController/ChannelListController.swift

Lines changed: 0 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -86,18 +86,6 @@ public class ChatChannelListController: DataController, DelegateCallable, DataSt
8686
$0.controller(self, didChangeChannels: changes)
8787
}
8888
}
89-
90-
observer.onWillChange = { [weak self] in
91-
self?.delegateCallback { [weak self] in
92-
guard let self = self else {
93-
log.warning("Callback called while self is nil")
94-
return
95-
}
96-
97-
$0.controllerWillChangeChannels(self)
98-
}
99-
}
100-
10189
return observer
10290
}()
10391

@@ -278,12 +266,6 @@ extension ChatChannelListController {
278266

279267
/// `ChatChannelListController` uses this protocol to communicate changes to its delegate.
280268
public protocol ChatChannelListControllerDelegate: DataControllerStateDelegate {
281-
/// The controller will update the list of observed channels.
282-
///
283-
/// - Parameter controller: The controller emitting the change callback.
284-
///
285-
func controllerWillChangeChannels(_ controller: ChatChannelListController)
286-
287269
/// The controller changed the list of observed channels.
288270
///
289271
/// - Parameters:
@@ -297,8 +279,6 @@ public protocol ChatChannelListControllerDelegate: DataControllerStateDelegate {
297279
}
298280

299281
public extension ChatChannelListControllerDelegate {
300-
func controllerWillChangeChannels(_ controller: ChatChannelListController) {}
301-
302282
func controller(
303283
_ controller: ChatChannelListController,
304284
didChangeChannels changes: [ListChange<ChatChannel>]

Sources/StreamChat/Controllers/DatabaseObserver/BackgroundDatabaseObserver.swift

Lines changed: 1 addition & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -6,10 +6,6 @@ import CoreData
66
import Foundation
77

88
class BackgroundDatabaseObserver<Item: Sendable, DTO: NSManagedObject>: @unchecked Sendable {
9-
/// Called with the aggregated changes after the internal `NSFetchResultsController` calls `controllerWillChangeContent`
10-
/// on its delegate.
11-
var onWillChange: (@Sendable () -> Void)?
12-
139
/// Called with the aggregated changes after the internal `NSFetchResultsController` calls `controllerDidChangeContent`
1410
/// on its delegate.
1511
var onDidChange: (@Sendable ([ListChange<Item>]) -> Void)?
@@ -30,24 +26,10 @@ class BackgroundDatabaseObserver<Item: Sendable, DTO: NSManagedObject>: @uncheck
3026

3127
private let queue = DispatchQueue(label: "io.getstream.list-database-observer", qos: .userInitiated)
3228
private var _items: [Item]?
33-
34-
// State handling for supporting will change, because in the callback we should return the previous state.
35-
private var _willChangeItems: [Item]?
36-
private var _notifyingWillChange = false
3729

3830
/// The items that have been fetched and mapped
3931
var rawItems: [Item] {
40-
// During the onWillChange we swap the results back to the previous state because onWillChange
41-
// is dispatched to the main thread and when the main thread handles it, observer has already processed
42-
// the database change.
43-
if onWillChange != nil {
44-
let willChangeState: (active: Bool, cachedItems: [Item]?) = queue.sync { (_notifyingWillChange, _willChangeItems) }
45-
if willChangeState.active {
46-
return willChangeState.cachedItems ?? []
47-
}
48-
}
49-
50-
var rawItems: [Item]!
32+
nonisolated(unsafe) var rawItems: [Item]!
5133
frc.managedObjectContext.performAndWait {
5234
// When we already have loaded items, reuse them, otherwise refetch all
5335
rawItems = _items ?? updateItems(nil)
@@ -98,9 +80,6 @@ class BackgroundDatabaseObserver<Item: Sendable, DTO: NSManagedObject>: @uncheck
9880
sectionNameKeyPath: nil,
9981
cacheName: nil
10082
)
101-
changeAggregator.onWillChange = { [weak self] in
102-
self?.notifyWillChange()
103-
}
10483
changeAggregator.onDidChange = { [weak self] changes in
10584
guard let self else { return }
10685
// Runs on the NSManagedObjectContext's queue, therefore skip performAndWait
@@ -133,33 +112,6 @@ class BackgroundDatabaseObserver<Item: Sendable, DTO: NSManagedObject>: @uncheck
133112
}
134113
}
135114

136-
private func notifyWillChange() {
137-
guard let onWillChange = onWillChange else {
138-
return
139-
}
140-
// Will change callback happens on the main thread but by that time the observer
141-
// has already updated its local cached state. For allowing to access the previous
142-
// state from the will change callback, there is no other way than caching previous state.
143-
// This is used by the channel list delegate.
144-
145-
// `_items` is mutated by the NSManagedObjectContext's queue, here we are on that queue
146-
// so it is safe to read the `_items` state from `self.queue`.
147-
queue.sync {
148-
_willChangeItems = _items
149-
}
150-
DispatchQueue.main.async { [weak self] in
151-
guard let self else { return }
152-
self.queue.async {
153-
self._notifyingWillChange = true
154-
}
155-
onWillChange()
156-
self.queue.async {
157-
self._willChangeItems = nil
158-
self._notifyingWillChange = false
159-
}
160-
}
161-
}
162-
163115
private func notifyDidChange(changes: [ListChange<Item>]) {
164116
guard let onDidChange = onDidChange else {
165117
return

Sources/StreamChat/Controllers/DatabaseObserver/ListChange.swift

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -144,10 +144,6 @@ class ListChangeAggregator<DTO: NSManagedObject, Item>: NSObject, NSFetchedResul
144144
/// Used for converting the `DTO`s provided by `FetchResultsController` to the resulting `Item`.
145145
let itemCreator: (DTO) throws -> Item
146146

147-
/// Called when the aggregator is about to change the current content. It gets called when the `FetchedResultsController`
148-
/// calls `controllerWillChangeContent` on its delegate.
149-
var onWillChange: (() -> Void)?
150-
151147
/// Called with the aggregated changes after `FetchResultsController` calls controllerDidChangeContent` on its delegate.
152148
var onDidChange: (([ListChange<Item>]) -> Void)?
153149

@@ -167,7 +163,6 @@ class ListChangeAggregator<DTO: NSManagedObject, Item>: NSObject, NSFetchedResul
167163
// This should ideally be in the extensions but it's not possible to implement @objc methods in extensions of generic types.
168164

169165
func controllerWillChangeContent(_ controller: NSFetchedResultsController<NSFetchRequestResult>) {
170-
onWillChange?()
171166
currentChanges = []
172167
}
173168

Sources/StreamChatUI/ChatChannelList/ChatChannelListVC.swift

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -403,10 +403,6 @@ open class ChatChannelListVC: _ViewController,
403403

404404
// MARK: - ChatChannelListControllerDelegate
405405

406-
open func controllerWillChangeChannels(_ controller: ChatChannelListController) {
407-
collectionView.layoutIfNeeded()
408-
}
409-
410406
open func controller(
411407
_ controller: ChatChannelListController,
412408
didChangeChannels changes: [ListChange<ChatChannel>]

TestTools/StreamChatTestTools/SpyPattern/QueueAware/ChannelListController_Delegate.swift

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -8,19 +8,13 @@ import Foundation
88
// A concrete `ChannelListControllerDelegate` implementation allowing capturing the delegate calls
99
final class ChannelListController_Delegate: QueueAwareDelegate, ChatChannelListControllerDelegate {
1010
@Atomic var state: DataController.State?
11-
@Atomic var willChangeChannels_called = false
1211
@Atomic var didChangeChannels_changes: [ListChange<ChatChannel>]?
1312

1413
func controller(_ controller: DataController, didChangeState state: DataController.State) {
1514
self.state = state
1615
validateQueue()
1716
}
1817

19-
func controllerWillChangeChannels(_ controller: ChatChannelListController) {
20-
willChangeChannels_called = true
21-
validateQueue()
22-
}
23-
2418
func controller(
2519
_ controller: ChatChannelListController,
2620
didChangeChannels changes: [ListChange<ChatChannel>]

Tests/StreamChatTests/Controllers/ChannelListController/ChannelListController_Tests.swift

Lines changed: 1 addition & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -651,38 +651,26 @@ final class ChannelListController_Tests: XCTestCase {
651651
let channel = try XCTUnwrap(client.databaseContainer.viewContext.channel(cid: cid)).asModel()
652652

653653
AssertAsync {
654-
Assert.willBeTrue(delegate.willChangeChannels_called)
655654
Assert.willBeEqual(delegate.didChangeChannels_changes, [.insert(channel, index: [0, 0])])
656655
}
657656
}
658657

659-
@MainActor func test_willAndDidCallbacks_areCalledInCorrectOrder() throws {
658+
@MainActor func test_didCallbacks_areCalledInCorrectOrder() throws {
660659
class Delegate: ChatChannelListControllerDelegate {
661660
let cid: ChannelId
662661

663-
var willChangeCallbackCalled = false
664662
var didChangeCallbackCalled = false
665663

666664
init(cid: ChannelId) {
667665
self.cid = cid
668666
}
669667

670-
func controllerWillChangeChannels(_ controller: ChatChannelListController) {
671-
// Check the new channel is NOT in reported channels yet
672-
XCTAssertFalse(controller.channels.contains { $0.cid == cid })
673-
// Assert the "did" callback hasn't been called yet
674-
XCTAssertFalse(didChangeCallbackCalled)
675-
willChangeCallbackCalled = true
676-
}
677-
678668
func controller(
679669
_ controller: ChatChannelListController,
680670
didChangeChannels changes: [ListChange<ChatChannel>]
681671
) {
682672
// Check the new channel is in reported channels
683673
XCTAssertTrue(controller.channels.contains { $0.cid == cid })
684-
// Assert the "will" callback has been called
685-
XCTAssertTrue(willChangeCallbackCalled)
686674
didChangeCallbackCalled = true
687675
}
688676
}
@@ -699,7 +687,6 @@ final class ChannelListController_Tests: XCTestCase {
699687
}
700688

701689
AssertAsync {
702-
Assert.willBeTrue(delegate.willChangeCallbackCalled)
703690
Assert.willBeTrue(delegate.didChangeCallbackCalled)
704691
}
705692
}

Tests/StreamChatTests/Controllers/MessageController/MessageController_Tests.swift

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -905,9 +905,8 @@ final class MessageController_Tests: XCTestCase {
905905

906906
func test_deleteMessageForMe_propagatesError() {
907907
// Simulate `deleteMessageForMe` call and catch the completion
908-
var completionError: Error?
909-
controller.deleteMessageForMe { [callbackQueueID] in
910-
AssertTestQueue(withId: callbackQueueID)
908+
nonisolated(unsafe) var completionError: Error?
909+
controller.deleteMessageForMe {
911910
completionError = $0
912911
}
913912

@@ -921,9 +920,8 @@ final class MessageController_Tests: XCTestCase {
921920

922921
func test_deleteMessageForMe_propagatesNilError() {
923922
// Simulate `deleteMessageForMe` call and catch the completion
924-
var completionCalled = false
925-
controller.deleteMessageForMe { [callbackQueueID] in
926-
AssertTestQueue(withId: callbackQueueID)
923+
nonisolated(unsafe) var completionCalled = false
924+
controller.deleteMessageForMe {
927925
XCTAssertNil($0)
928926
completionCalled = true
929927
}

Tests/StreamChatTests/ListChangeAggregator_Tests.swift

Lines changed: 0 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -29,16 +29,6 @@ final class ListChangeAggregator_Tests: XCTestCase {
2929
super.tearDown()
3030
}
3131

32-
func test_onWillChange_isCalled() {
33-
// Set up aggregator callback
34-
var callbackCalled = false
35-
aggregator.onWillChange = { callbackCalled = true }
36-
37-
// Simulate FRC starts updating
38-
aggregator.controllerWillChangeContent(fakeController)
39-
XCTAssertTrue(callbackCalled)
40-
}
41-
4232
func test_addingItems() {
4333
// Set up aggregator callback
4434
var result: [ListChange<String>]?

0 commit comments

Comments
 (0)