From 2f314f560fc7f0e3cdcd82f9947a12aac91246d7 Mon Sep 17 00:00:00 2001 From: bachvq Date: Thu, 6 Apr 2023 17:22:53 +0700 Subject: [PATCH 01/10] fix bugs --- ...dableSectionController+DifferenceKit.swift | 121 +++++++++--------- 1 file changed, 63 insertions(+), 58 deletions(-) diff --git a/Comier/Classes/AS+IGListKit/COListBindableSectionController+DifferenceKit.swift b/Comier/Classes/AS+IGListKit/COListBindableSectionController+DifferenceKit.swift index 036edf1..6283d78 100644 --- a/Comier/Classes/AS+IGListKit/COListBindableSectionController+DifferenceKit.swift +++ b/Comier/Classes/AS+IGListKit/COListBindableSectionController+DifferenceKit.swift @@ -113,70 +113,75 @@ open class ASListBindingSectionController: COSectionContr return } self.state = .queued - self.collectionContext?.performBatch(animated: animated, updates: { [weak self] (batchContext) in - guard let self = self, self.state == .queued else {return} + DispatchQueue.global().async { [weak self] in + guard let self else {return} let object = self.object - let copyViewModels = self.viewModels.map({$0}) - let oldViewModels = copyViewModels - let newViewModels = self.dataSource?.viewModels(for: object) + let newViewModels = self.dataSource?.viewModels(for: object as Any) let filterVM = objectsWithDuplicateIdentifiersRemoved(newViewModels) ?? [] - let result = ListDiff(oldArray: oldViewModels, newArray: filterVM, option: .equality) - guard result.hasChanges else {return} - self.viewModels = filterVM - - if !result.updates.isEmpty { - var indexReloads: [Int] = [] - for oldIndex in result.updates { - guard oldIndex < oldViewModels.count else {break} - if shouldUpdateCell { - let id = oldViewModels[oldIndex].diffIdentifier() - let indexAfterUpdate = result.newIndex(forIdentifier: id) - if indexAfterUpdate != NSNotFound { - if let cell = self.context.nodeForItem(at: oldIndex, section: self) { - let node = cell as? ListBindable - node?.bindViewModel(filterVM[indexAfterUpdate]) - } else { - indexReloads.append(oldIndex) + let boxs = filterVM.map({DiffBox(value: $0)}) + let oldViewModels = viewModels.map({DiffBox(value: $0)}) + let stageChanged = StagedChangeset(source: oldViewModels, target: boxs, section: section) + DispatchQueue.main.async { [weak self] in + guard let self else {return} + self.collectionContext?.performBatch(animated: animated, updates: { [weak self] (batchContext) in + guard let self = self, self.state == .queued else {return} + + guard !stageChanged.isEmpty else {return} + + for stage in stageChanged { + let changeData = stage.data.map({$0}) + + if let ex = self.collectionContext?.experiments, !stage.elementUpdated.isEmpty, ListExperimentEnabled(mask: ex, option: IGListExperiment.invalidateLayoutForUpdates) { + batchContext.invalidateLayout(in: self, at: IndexSet(stage.elementUpdated.map({$0.element}))) + } + + self.viewModels = stage.data.map({$0.value}) + if !stage.elementUpdated.isEmpty { + var indexReloads: [Int] = [] + for indexPath in stage.elementUpdated { + let index = indexPath.element + if shouldUpdateCell { + let value = changeData[indexPath.element].value + if let cell = self.context.nodeForItem(at: index, section: self) { + let node = cell as? ListBindable + node?.bindViewModel(value) + } else { + indexReloads.append(indexPath.element) + } + } else { + indexReloads.append(indexPath.element) + } + } + if !indexReloads.isEmpty { + batchContext.reload(in: self, at: IndexSet(indexReloads)) } } - } else { - indexReloads.append(oldIndex) - } - } - if !indexReloads.isEmpty { - batchContext.reload(in: self, at: IndexSet(indexReloads)) - } - } - - if let ex = self.collectionContext?.experiments, !result.updates.isEmpty, ListExperimentEnabled(mask: ex, option: IGListExperiment.invalidateLayoutForUpdates) { - batchContext.invalidateLayout(in: self, at: result.updates) - } - - if !result.deletes.isEmpty { - batchContext.delete(in: self, at: result.deletes) - } + + if !stage.elementDeleted.isEmpty { + batchContext.delete(in: self, at: IndexSet(stage.elementDeleted.map({$0.element}))) + } - if !result.inserts.isEmpty { - batchContext.insert(in: self, at: result.inserts) - } - - if !result.moves.isEmpty { - for move in result.moves { - batchContext.move(in: self, from: move.from, to: move.to) - } - } - - self.state = .applied - }, completion: { [weak self] (finished) in - completion?(finished) - if finished, let self = self { - self.state = .idle - if let wait = self.lastWaitForUpdate { - self.lastWaitForUpdate = nil - self.updateAnimated(animated: wait.animated, shouldUpdateCell: wait.shouldUpdateCell, completion: wait.completion) - } + if !stage.elementInserted.isEmpty { + batchContext.insert(in: self, at: IndexSet(stage.elementInserted.map({$0.element}))) + } + + if !stage.elementMoved.isEmpty { + for move in stage.elementMoved { + batchContext.move(in: self, from: move.source.element, to: move.target.element) + } + } + } + self.state = .applied + }, completion: { [weak self] (finished) in + completion?(finished) + self?.state = .idle + if let wait = self?.lastWaitForUpdate { + self?.lastWaitForUpdate = nil + self?.updateAnimated(animated: wait.animated, shouldUpdateCell: wait.shouldUpdateCell, completion: wait.completion) + } + }) } - }) + } } deinit { From b5a335e99706eddaf82abeaaf085b7b6569a5540 Mon Sep 17 00:00:00 2001 From: jbach Date: Thu, 6 Apr 2023 19:03:48 +0700 Subject: [PATCH 02/10] fix crash --- ...dableSectionController+DifferenceKit.swift | 115 +++++++++--------- 1 file changed, 59 insertions(+), 56 deletions(-) diff --git a/Comier/Classes/AS+IGListKit/COListBindableSectionController+DifferenceKit.swift b/Comier/Classes/AS+IGListKit/COListBindableSectionController+DifferenceKit.swift index 6283d78..8746184 100644 --- a/Comier/Classes/AS+IGListKit/COListBindableSectionController+DifferenceKit.swift +++ b/Comier/Classes/AS+IGListKit/COListBindableSectionController+DifferenceKit.swift @@ -35,7 +35,6 @@ enum SectionState { } open class ASListBindingSectionController: COSectionController { - public typealias SectionModel = Element public var viewModels: [ListDiffable] = [] @@ -120,67 +119,71 @@ open class ASListBindingSectionController: COSectionContr let filterVM = objectsWithDuplicateIdentifiersRemoved(newViewModels) ?? [] let boxs = filterVM.map({DiffBox(value: $0)}) let oldViewModels = viewModels.map({DiffBox(value: $0)}) - let stageChanged = StagedChangeset(source: oldViewModels, target: boxs, section: section) + let stageChanged = StagedChangeset(source: oldViewModels, target: boxs, section: 0) DispatchQueue.main.async { [weak self] in guard let self else {return} - self.collectionContext?.performBatch(animated: animated, updates: { [weak self] (batchContext) in - guard let self = self, self.state == .queued else {return} - - guard !stageChanged.isEmpty else {return} - - for stage in stageChanged { - let changeData = stage.data.map({$0}) - - if let ex = self.collectionContext?.experiments, !stage.elementUpdated.isEmpty, ListExperimentEnabled(mask: ex, option: IGListExperiment.invalidateLayoutForUpdates) { - batchContext.invalidateLayout(in: self, at: IndexSet(stage.elementUpdated.map({$0.element}))) - } - - self.viewModels = stage.data.map({$0.value}) - if !stage.elementUpdated.isEmpty { - var indexReloads: [Int] = [] - for indexPath in stage.elementUpdated { - let index = indexPath.element - if shouldUpdateCell { - let value = changeData[indexPath.element].value - if let cell = self.context.nodeForItem(at: index, section: self) { - let node = cell as? ListBindable - node?.bindViewModel(value) - } else { - indexReloads.append(indexPath.element) - } - } else { - indexReloads.append(indexPath.element) - } - } - if !indexReloads.isEmpty { - batchContext.reload(in: self, at: IndexSet(indexReloads)) - } - } - - if !stage.elementDeleted.isEmpty { - batchContext.delete(in: self, at: IndexSet(stage.elementDeleted.map({$0.element}))) - } - - if !stage.elementInserted.isEmpty { - batchContext.insert(in: self, at: IndexSet(stage.elementInserted.map({$0.element}))) - } - - if !stage.elementMoved.isEmpty { - for move in stage.elementMoved { - batchContext.move(in: self, from: move.source.element, to: move.target.element) + performUpdate(stageChanged: stageChanged, animated: animated, shouldUpdateCell: shouldUpdateCell, completion: completion) + } + } + } + + private func performUpdate(stageChanged: StagedChangeset<[DiffBox]>, animated: Bool, shouldUpdateCell: Bool, completion: ((Bool) -> Void)? = nil) { + for stage in stageChanged { + self.collectionContext?.performBatch(animated: animated, updates: { [weak self] (batchContext) in + guard let self = self, self.state == .queued else {return} + + guard !stageChanged.isEmpty else {return} + + let changeData = stage.data.map({$0.value}) + self.viewModels = changeData + + if let ex = self.collectionContext?.experiments, !stage.elementUpdated.isEmpty, ListExperimentEnabled(mask: ex, option: IGListExperiment.invalidateLayoutForUpdates) { + batchContext.invalidateLayout(in: self, at: IndexSet(stage.elementUpdated.map({$0.element}))) + } + + if !stage.elementUpdated.isEmpty { + var indexReloads: [Int] = [] + for indexPath in stage.elementUpdated { + let index = indexPath.element + if shouldUpdateCell { + let value = changeData[indexPath.element] + if let cell = self.context.nodeForItem(at: index, section: self) { + let node = cell as? ListBindable + node?.bindViewModel(value) + } else { + indexReloads.append(indexPath.element) } + } else { + indexReloads.append(indexPath.element) } } - self.state = .applied - }, completion: { [weak self] (finished) in - completion?(finished) - self?.state = .idle - if let wait = self?.lastWaitForUpdate { - self?.lastWaitForUpdate = nil - self?.updateAnimated(animated: wait.animated, shouldUpdateCell: wait.shouldUpdateCell, completion: wait.completion) + if !indexReloads.isEmpty { + batchContext.reload(in: self, at: IndexSet(indexReloads)) } - }) - } + } + + if !stage.elementDeleted.isEmpty { + batchContext.delete(in: self, at: IndexSet(stage.elementDeleted.map({$0.element}))) + } + + if !stage.elementInserted.isEmpty { + batchContext.insert(in: self, at: IndexSet(stage.elementInserted.map({$0.element}))) + } + + if !stage.elementMoved.isEmpty { + for move in stage.elementMoved { + batchContext.move(in: self, from: move.source.element, to: move.target.element) + } + } + self.state = .applied + }, completion: { [weak self] (finished) in + completion?(finished) + self?.state = .idle + if let wait = self?.lastWaitForUpdate { + self?.lastWaitForUpdate = nil + self?.updateAnimated(animated: wait.animated, shouldUpdateCell: wait.shouldUpdateCell, completion: wait.completion) + } + }) } } From 977445197cf6e217a2c58996ab9dd733dc52eccf Mon Sep 17 00:00:00 2001 From: jbach Date: Thu, 6 Apr 2023 19:05:51 +0700 Subject: [PATCH 03/10] fix crash --- ...istBindableSectionController+DifferenceKit.swift | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/Comier/Classes/AS+IGListKit/COListBindableSectionController+DifferenceKit.swift b/Comier/Classes/AS+IGListKit/COListBindableSectionController+DifferenceKit.swift index 8746184..1b210e8 100644 --- a/Comier/Classes/AS+IGListKit/COListBindableSectionController+DifferenceKit.swift +++ b/Comier/Classes/AS+IGListKit/COListBindableSectionController+DifferenceKit.swift @@ -111,7 +111,6 @@ open class ASListBindingSectionController: COSectionContr self.lastWaitForUpdate = (animated, shouldUpdateCell, completion) return } - self.state = .queued DispatchQueue.global().async { [weak self] in guard let self else {return} let object = self.object @@ -175,14 +174,14 @@ open class ASListBindingSectionController: COSectionContr batchContext.move(in: self, from: move.source.element, to: move.target.element) } } - self.state = .applied +// self.state = .applied }, completion: { [weak self] (finished) in completion?(finished) - self?.state = .idle - if let wait = self?.lastWaitForUpdate { - self?.lastWaitForUpdate = nil - self?.updateAnimated(animated: wait.animated, shouldUpdateCell: wait.shouldUpdateCell, completion: wait.completion) - } +// self?.state = .idle +// if let wait = self?.lastWaitForUpdate { +// self?.lastWaitForUpdate = nil +// self?.updateAnimated(animated: wait.animated, shouldUpdateCell: wait.shouldUpdateCell, completion: wait.completion) +// } }) } } From 06caefca921e83ae1091ddbccb1daa513924d766 Mon Sep 17 00:00:00 2001 From: jbach Date: Thu, 6 Apr 2023 19:18:37 +0700 Subject: [PATCH 04/10] fix crash --- .../COListBindableSectionController+DifferenceKit.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Comier/Classes/AS+IGListKit/COListBindableSectionController+DifferenceKit.swift b/Comier/Classes/AS+IGListKit/COListBindableSectionController+DifferenceKit.swift index 1b210e8..4db32f7 100644 --- a/Comier/Classes/AS+IGListKit/COListBindableSectionController+DifferenceKit.swift +++ b/Comier/Classes/AS+IGListKit/COListBindableSectionController+DifferenceKit.swift @@ -129,7 +129,7 @@ open class ASListBindingSectionController: COSectionContr private func performUpdate(stageChanged: StagedChangeset<[DiffBox]>, animated: Bool, shouldUpdateCell: Bool, completion: ((Bool) -> Void)? = nil) { for stage in stageChanged { self.collectionContext?.performBatch(animated: animated, updates: { [weak self] (batchContext) in - guard let self = self, self.state == .queued else {return} + guard let self = self else {return} guard !stageChanged.isEmpty else {return} From 12b6e824ef473add9d3bfed1a8b3c4a63215d1b9 Mon Sep 17 00:00:00 2001 From: jbach Date: Thu, 6 Apr 2023 19:34:04 +0700 Subject: [PATCH 05/10] fix crash --- ...dableSectionController+DifferenceKit.swift | 102 +++++++++--------- 1 file changed, 52 insertions(+), 50 deletions(-) diff --git a/Comier/Classes/AS+IGListKit/COListBindableSectionController+DifferenceKit.swift b/Comier/Classes/AS+IGListKit/COListBindableSectionController+DifferenceKit.swift index 4db32f7..55c8153 100644 --- a/Comier/Classes/AS+IGListKit/COListBindableSectionController+DifferenceKit.swift +++ b/Comier/Classes/AS+IGListKit/COListBindableSectionController+DifferenceKit.swift @@ -118,7 +118,7 @@ open class ASListBindingSectionController: COSectionContr let filterVM = objectsWithDuplicateIdentifiersRemoved(newViewModels) ?? [] let boxs = filterVM.map({DiffBox(value: $0)}) let oldViewModels = viewModels.map({DiffBox(value: $0)}) - let stageChanged = StagedChangeset(source: oldViewModels, target: boxs, section: 0) + let stageChanged = StagedChangeset(source: boxs, target: oldViewModels) DispatchQueue.main.async { [weak self] in guard let self else {return} performUpdate(stageChanged: stageChanged, animated: animated, shouldUpdateCell: shouldUpdateCell, completion: completion) @@ -127,62 +127,64 @@ open class ASListBindingSectionController: COSectionContr } private func performUpdate(stageChanged: StagedChangeset<[DiffBox]>, animated: Bool, shouldUpdateCell: Bool, completion: ((Bool) -> Void)? = nil) { - for stage in stageChanged { - self.collectionContext?.performBatch(animated: animated, updates: { [weak self] (batchContext) in - guard let self = self else {return} - - guard !stageChanged.isEmpty else {return} - - let changeData = stage.data.map({$0.value}) - self.viewModels = changeData - - if let ex = self.collectionContext?.experiments, !stage.elementUpdated.isEmpty, ListExperimentEnabled(mask: ex, option: IGListExperiment.invalidateLayoutForUpdates) { - batchContext.invalidateLayout(in: self, at: IndexSet(stage.elementUpdated.map({$0.element}))) - } - - if !stage.elementUpdated.isEmpty { - var indexReloads: [Int] = [] - for indexPath in stage.elementUpdated { - let index = indexPath.element - if shouldUpdateCell { - let value = changeData[indexPath.element] - if let cell = self.context.nodeForItem(at: index, section: self) { - let node = cell as? ListBindable - node?.bindViewModel(value) + if let stage = stageChanged.last { +// for stage in stageChanged { + self.collectionContext?.performBatch(animated: animated, updates: { [weak self] (batchContext) in + guard let self = self else {return} + +// guard !stageChanged.isEmpty else {return} + + let changeData = stage.data.map({$0.value}) + self.viewModels = changeData + + if let ex = self.collectionContext?.experiments, !stage.elementUpdated.isEmpty, ListExperimentEnabled(mask: ex, option: IGListExperiment.invalidateLayoutForUpdates) { + batchContext.invalidateLayout(in: self, at: IndexSet(stage.elementUpdated.map({$0.element}))) + } + + if !stage.elementUpdated.isEmpty { + var indexReloads: [Int] = [] + for indexPath in stage.elementUpdated { + let index = indexPath.element + if shouldUpdateCell { + let value = changeData[indexPath.element] + if let cell = self.context.nodeForItem(at: index, section: self) { + let node = cell as? ListBindable + node?.bindViewModel(value) + } else { + indexReloads.append(indexPath.element) + } } else { indexReloads.append(indexPath.element) } - } else { - indexReloads.append(indexPath.element) + } + if !indexReloads.isEmpty { + batchContext.reload(in: self, at: IndexSet(indexReloads)) } } - if !indexReloads.isEmpty { - batchContext.reload(in: self, at: IndexSet(indexReloads)) + + if !stage.elementDeleted.isEmpty { + batchContext.delete(in: self, at: IndexSet(stage.elementDeleted.map({$0.element}))) } - } - - if !stage.elementDeleted.isEmpty { - batchContext.delete(in: self, at: IndexSet(stage.elementDeleted.map({$0.element}))) - } - - if !stage.elementInserted.isEmpty { - batchContext.insert(in: self, at: IndexSet(stage.elementInserted.map({$0.element}))) - } - - if !stage.elementMoved.isEmpty { - for move in stage.elementMoved { - batchContext.move(in: self, from: move.source.element, to: move.target.element) + + if !stage.elementInserted.isEmpty { + batchContext.insert(in: self, at: IndexSet(stage.elementInserted.map({$0.element}))) + } + + if !stage.elementMoved.isEmpty { + for move in stage.elementMoved { + batchContext.move(in: self, from: move.source.element, to: move.target.element) + } } - } -// self.state = .applied - }, completion: { [weak self] (finished) in - completion?(finished) -// self?.state = .idle -// if let wait = self?.lastWaitForUpdate { -// self?.lastWaitForUpdate = nil -// self?.updateAnimated(animated: wait.animated, shouldUpdateCell: wait.shouldUpdateCell, completion: wait.completion) -// } - }) + // self.state = .applied + }, completion: { [weak self] (finished) in + completion?(finished) + // self?.state = .idle + // if let wait = self?.lastWaitForUpdate { + // self?.lastWaitForUpdate = nil + // self?.updateAnimated(animated: wait.animated, shouldUpdateCell: wait.shouldUpdateCell, completion: wait.completion) + // } + }) +// } } } From 3ea6310a4af34af5af88591a869b880bbd88765a Mon Sep 17 00:00:00 2001 From: jbach Date: Thu, 6 Apr 2023 19:37:04 +0700 Subject: [PATCH 06/10] fix crash --- .../COListBindableSectionController+DifferenceKit.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Comier/Classes/AS+IGListKit/COListBindableSectionController+DifferenceKit.swift b/Comier/Classes/AS+IGListKit/COListBindableSectionController+DifferenceKit.swift index 55c8153..383b810 100644 --- a/Comier/Classes/AS+IGListKit/COListBindableSectionController+DifferenceKit.swift +++ b/Comier/Classes/AS+IGListKit/COListBindableSectionController+DifferenceKit.swift @@ -118,7 +118,7 @@ open class ASListBindingSectionController: COSectionContr let filterVM = objectsWithDuplicateIdentifiersRemoved(newViewModels) ?? [] let boxs = filterVM.map({DiffBox(value: $0)}) let oldViewModels = viewModels.map({DiffBox(value: $0)}) - let stageChanged = StagedChangeset(source: boxs, target: oldViewModels) + let stageChanged = StagedChangeset(source: oldViewModels, target: boxs) DispatchQueue.main.async { [weak self] in guard let self else {return} performUpdate(stageChanged: stageChanged, animated: animated, shouldUpdateCell: shouldUpdateCell, completion: completion) From 01dadaf89aadf961a8443d07c05c61d00ed97116 Mon Sep 17 00:00:00 2001 From: jbach Date: Thu, 6 Apr 2023 19:47:09 +0700 Subject: [PATCH 07/10] reverb --- ...dableSectionController+DifferenceKit.swift | 100 +++++++++--------- 1 file changed, 49 insertions(+), 51 deletions(-) diff --git a/Comier/Classes/AS+IGListKit/COListBindableSectionController+DifferenceKit.swift b/Comier/Classes/AS+IGListKit/COListBindableSectionController+DifferenceKit.swift index 383b810..1bfc873 100644 --- a/Comier/Classes/AS+IGListKit/COListBindableSectionController+DifferenceKit.swift +++ b/Comier/Classes/AS+IGListKit/COListBindableSectionController+DifferenceKit.swift @@ -127,64 +127,62 @@ open class ASListBindingSectionController: COSectionContr } private func performUpdate(stageChanged: StagedChangeset<[DiffBox]>, animated: Bool, shouldUpdateCell: Bool, completion: ((Bool) -> Void)? = nil) { - if let stage = stageChanged.last { -// for stage in stageChanged { - self.collectionContext?.performBatch(animated: animated, updates: { [weak self] (batchContext) in - guard let self = self else {return} - -// guard !stageChanged.isEmpty else {return} - - let changeData = stage.data.map({$0.value}) - self.viewModels = changeData - - if let ex = self.collectionContext?.experiments, !stage.elementUpdated.isEmpty, ListExperimentEnabled(mask: ex, option: IGListExperiment.invalidateLayoutForUpdates) { - batchContext.invalidateLayout(in: self, at: IndexSet(stage.elementUpdated.map({$0.element}))) - } - - if !stage.elementUpdated.isEmpty { - var indexReloads: [Int] = [] - for indexPath in stage.elementUpdated { - let index = indexPath.element - if shouldUpdateCell { - let value = changeData[indexPath.element] - if let cell = self.context.nodeForItem(at: index, section: self) { - let node = cell as? ListBindable - node?.bindViewModel(value) - } else { - indexReloads.append(indexPath.element) - } + for stage in stageChanged { + self.collectionContext?.performBatch(animated: animated, updates: { [weak self] (batchContext) in + guard let self = self else {return} + + guard !stageChanged.isEmpty else {return} + + let changeData = stage.data.map({$0.value}) + self.viewModels = changeData + + if let ex = self.collectionContext?.experiments, !stage.elementUpdated.isEmpty, ListExperimentEnabled(mask: ex, option: IGListExperiment.invalidateLayoutForUpdates) { + batchContext.invalidateLayout(in: self, at: IndexSet(stage.elementUpdated.map({$0.element}))) + } + + if !stage.elementUpdated.isEmpty { + var indexReloads: [Int] = [] + for indexPath in stage.elementUpdated { + let index = indexPath.element + if shouldUpdateCell { + let value = changeData[indexPath.element] + if let cell = self.context.nodeForItem(at: index, section: self) { + let node = cell as? ListBindable + node?.bindViewModel(value) } else { indexReloads.append(indexPath.element) } - } - if !indexReloads.isEmpty { - batchContext.reload(in: self, at: IndexSet(indexReloads)) + } else { + indexReloads.append(indexPath.element) } } - - if !stage.elementDeleted.isEmpty { - batchContext.delete(in: self, at: IndexSet(stage.elementDeleted.map({$0.element}))) + if !indexReloads.isEmpty { + batchContext.reload(in: self, at: IndexSet(indexReloads)) } - - if !stage.elementInserted.isEmpty { - batchContext.insert(in: self, at: IndexSet(stage.elementInserted.map({$0.element}))) - } - - if !stage.elementMoved.isEmpty { - for move in stage.elementMoved { - batchContext.move(in: self, from: move.source.element, to: move.target.element) - } + } + + if !stage.elementDeleted.isEmpty { + batchContext.delete(in: self, at: IndexSet(stage.elementDeleted.map({$0.element}))) + } + + if !stage.elementInserted.isEmpty { + batchContext.insert(in: self, at: IndexSet(stage.elementInserted.map({$0.element}))) + } + + if !stage.elementMoved.isEmpty { + for move in stage.elementMoved { + batchContext.move(in: self, from: move.source.element, to: move.target.element) } - // self.state = .applied - }, completion: { [weak self] (finished) in - completion?(finished) - // self?.state = .idle - // if let wait = self?.lastWaitForUpdate { - // self?.lastWaitForUpdate = nil - // self?.updateAnimated(animated: wait.animated, shouldUpdateCell: wait.shouldUpdateCell, completion: wait.completion) - // } - }) -// } + } + // self.state = .applied + }, completion: { [weak self] (finished) in + completion?(finished) + // self?.state = .idle + // if let wait = self?.lastWaitForUpdate { + // self?.lastWaitForUpdate = nil + // self?.updateAnimated(animated: wait.animated, shouldUpdateCell: wait.shouldUpdateCell, completion: wait.completion) + // } + }) } } From 09089d168183a6dd762317a83d98d034b47acd2c Mon Sep 17 00:00:00 2001 From: jbach Date: Thu, 6 Apr 2023 19:56:21 +0700 Subject: [PATCH 08/10] reverb --- ...dableSectionController+DifferenceKit.swift | 28 +++++++++++-------- 1 file changed, 17 insertions(+), 11 deletions(-) diff --git a/Comier/Classes/AS+IGListKit/COListBindableSectionController+DifferenceKit.swift b/Comier/Classes/AS+IGListKit/COListBindableSectionController+DifferenceKit.swift index 1bfc873..3527406 100644 --- a/Comier/Classes/AS+IGListKit/COListBindableSectionController+DifferenceKit.swift +++ b/Comier/Classes/AS+IGListKit/COListBindableSectionController+DifferenceKit.swift @@ -36,12 +36,12 @@ enum SectionState { open class ASListBindingSectionController: COSectionController { public typealias SectionModel = Element - + private var lockCount: Int = 0 public var viewModels: [ListDiffable] = [] public var object: SectionModel? = nil var state: SectionState = .idle - var lastWaitForUpdate: (animated: Bool, shouldUpdateCell: Bool, completion: ((Bool) -> Void)?)? = nil + var lastWaitForUpdate: (controller: COSectionController?, animated: Bool, shouldUpdateCell: Bool, completion: ((Bool) -> Void)?)? = nil public weak var dataSource: ASListBindingDataSource? = nil public weak var delegate: ASListBindingDelegate? = nil @@ -108,12 +108,13 @@ open class ASListBindingSectionController: COSectionContr public func updateAnimated(animated: Bool, shouldUpdateCell: Bool = true, completion: ((Bool) -> Void)? = nil) { guard self.object != nil else {return} if self.state != .idle { - self.lastWaitForUpdate = (animated, shouldUpdateCell, completion) + self.lastWaitForUpdate = (self, animated, shouldUpdateCell, completion) return } + self.state = .queued DispatchQueue.global().async { [weak self] in guard let self else {return} - let object = self.object + let object = (self.object as? NSObject)?.copy() let newViewModels = self.dataSource?.viewModels(for: object as Any) let filterVM = objectsWithDuplicateIdentifiersRemoved(newViewModels) ?? [] let boxs = filterVM.map({DiffBox(value: $0)}) @@ -127,6 +128,7 @@ open class ASListBindingSectionController: COSectionContr } private func performUpdate(stageChanged: StagedChangeset<[DiffBox]>, animated: Bool, shouldUpdateCell: Bool, completion: ((Bool) -> Void)? = nil) { + self.lockCount = stageChanged.count for stage in stageChanged { self.collectionContext?.performBatch(animated: animated, updates: { [weak self] (batchContext) in guard let self = self else {return} @@ -174,14 +176,18 @@ open class ASListBindingSectionController: COSectionContr batchContext.move(in: self, from: move.source.element, to: move.target.element) } } - // self.state = .applied + self.state = .applied }, completion: { [weak self] (finished) in - completion?(finished) - // self?.state = .idle - // if let wait = self?.lastWaitForUpdate { - // self?.lastWaitForUpdate = nil - // self?.updateAnimated(animated: wait.animated, shouldUpdateCell: wait.shouldUpdateCell, completion: wait.completion) - // } + self?.lockCount -= 1 + if self?.lockCount ?? 0 <= 0 { + self?.lockCount = 0 + self?.state = .idle + completion?(finished) + if let wait = self?.lastWaitForUpdate { + self?.lastWaitForUpdate = nil + self?.updateAnimated(animated: wait.animated, shouldUpdateCell: wait.shouldUpdateCell, completion: wait.completion) + } + } }) } } From bf4e8a5022c5eb60571d90996dc3da12389bdae6 Mon Sep 17 00:00:00 2001 From: jbach Date: Thu, 6 Apr 2023 20:11:08 +0700 Subject: [PATCH 09/10] reverb --- ...dableSectionController+DifferenceKit.swift | 31 ++++++++++++------- 1 file changed, 19 insertions(+), 12 deletions(-) diff --git a/Comier/Classes/AS+IGListKit/COListBindableSectionController+DifferenceKit.swift b/Comier/Classes/AS+IGListKit/COListBindableSectionController+DifferenceKit.swift index 3527406..31221e6 100644 --- a/Comier/Classes/AS+IGListKit/COListBindableSectionController+DifferenceKit.swift +++ b/Comier/Classes/AS+IGListKit/COListBindableSectionController+DifferenceKit.swift @@ -34,6 +34,13 @@ enum SectionState { case applied } +struct WaitItem { + let object: Any? + let animated: Bool + let shouldUpdateCell: Bool + let completion: ((Bool) -> Void)? +} + open class ASListBindingSectionController: COSectionController { public typealias SectionModel = Element private var lockCount: Int = 0 @@ -41,7 +48,7 @@ open class ASListBindingSectionController: COSectionContr public var object: SectionModel? = nil var state: SectionState = .idle - var lastWaitForUpdate: (controller: COSectionController?, animated: Bool, shouldUpdateCell: Bool, completion: ((Bool) -> Void)?)? = nil + var lastWaitForUpdate: WaitItem? = nil public weak var dataSource: ASListBindingDataSource? = nil public weak var delegate: ASListBindingDelegate? = nil @@ -78,13 +85,13 @@ open class ASListBindingSectionController: COSectionContr open override func didUpdate(to object: Any) { let firstUpdate = self.object == nil + let copyObj = object as? Element self.object = object as? Element - if firstUpdate { let viewModels = self.dataSource?.viewModels(for: object) self.viewModels = objectsWithDuplicateIdentifiersRemoved(viewModels) ?? [] } else { - self.updateAnimated(animated: willUpdateWithAnimation) + self.updateAnimated(object: object as? Element, animated: willUpdateWithAnimation) } } @@ -105,20 +112,22 @@ open class ASListBindingSectionController: COSectionContr return ASIGListSectionControllerMethods.cellForItem(at: index, sectionController: self) } - public func updateAnimated(animated: Bool, shouldUpdateCell: Bool = true, completion: ((Bool) -> Void)? = nil) { - guard self.object != nil else {return} + public func updateAnimated(object: Any?, animated: Bool, shouldUpdateCell: Bool = true, completion: ((Bool) -> Void)? = nil) { + guard let object else {return} if self.state != .idle { - self.lastWaitForUpdate = (self, animated, shouldUpdateCell, completion) + self.lastWaitForUpdate = .init(object: object, animated: animated, shouldUpdateCell: shouldUpdateCell, completion: completion) return } self.state = .queued DispatchQueue.global().async { [weak self] in guard let self else {return} - let object = (self.object as? NSObject)?.copy() let newViewModels = self.dataSource?.viewModels(for: object as Any) let filterVM = objectsWithDuplicateIdentifiersRemoved(newViewModels) ?? [] let boxs = filterVM.map({DiffBox(value: $0)}) - let oldViewModels = viewModels.map({DiffBox(value: $0)}) + let oldViewModels = viewModels.map({item in + let copy = item + return DiffBox(value: copy) + }) let stageChanged = StagedChangeset(source: oldViewModels, target: boxs) DispatchQueue.main.async { [weak self] in guard let self else {return} @@ -131,10 +140,8 @@ open class ASListBindingSectionController: COSectionContr self.lockCount = stageChanged.count for stage in stageChanged { self.collectionContext?.performBatch(animated: animated, updates: { [weak self] (batchContext) in - guard let self = self else {return} - + guard let self = self, self.state != .idle else {return} guard !stageChanged.isEmpty else {return} - let changeData = stage.data.map({$0.value}) self.viewModels = changeData @@ -185,7 +192,7 @@ open class ASListBindingSectionController: COSectionContr completion?(finished) if let wait = self?.lastWaitForUpdate { self?.lastWaitForUpdate = nil - self?.updateAnimated(animated: wait.animated, shouldUpdateCell: wait.shouldUpdateCell, completion: wait.completion) + self?.updateAnimated(object: wait.object ,animated: wait.animated, shouldUpdateCell: wait.shouldUpdateCell, completion: wait.completion) } } }) From 6d4280dce760cf895cd3588f5b51f0b246556c55 Mon Sep 17 00:00:00 2001 From: jbach Date: Thu, 6 Apr 2023 20:59:03 +0700 Subject: [PATCH 10/10] reverb --- .../COListBindableSectionController+DifferenceKit.swift | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Comier/Classes/AS+IGListKit/COListBindableSectionController+DifferenceKit.swift b/Comier/Classes/AS+IGListKit/COListBindableSectionController+DifferenceKit.swift index 31221e6..c3d380f 100644 --- a/Comier/Classes/AS+IGListKit/COListBindableSectionController+DifferenceKit.swift +++ b/Comier/Classes/AS+IGListKit/COListBindableSectionController+DifferenceKit.swift @@ -88,10 +88,10 @@ open class ASListBindingSectionController: COSectionContr let copyObj = object as? Element self.object = object as? Element if firstUpdate { - let viewModels = self.dataSource?.viewModels(for: object) + let viewModels = self.dataSource?.viewModels(for: copyObj ?? object) self.viewModels = objectsWithDuplicateIdentifiersRemoved(viewModels) ?? [] } else { - self.updateAnimated(object: object as? Element, animated: willUpdateWithAnimation) + self.updateAnimated(object: copyObj, animated: willUpdateWithAnimation) } }