Collection view freezes after upgrading from version 8.1.0 to 9.0.0 #407

Closed
opened 2025-12-29 15:31:05 +01:00 by adam · 5 comments
Owner

Originally created by @tmbiOS on GitHub (Mar 29, 2023).

Hi, John! @JohnEstropia
Thank you for you awesome library.
We use it in chat app with MessageKit. The problem appears when we migrated from 8.1.0 to 9.0.0 - collectionview starts freeze when scrolling. There is no such problem in the old version 8.1.0.
Please help, what we should check? Thanks.
Some peaces of code.

in AppDelegate:

let dataStack = DataStack(
        CoreStoreSchema(
            modelVersion: "V1",
            entities: [
                Entity<CategoryStoreObject>("CategoryStoreObject"),
                Entity<ChatStoreObject>("ChatStoreObject"),
                Entity<MessageStoreObject>("MessageStoreObject"),
                Entity<ProfileStoreObject>("ProfileStoreObject")
            ]
        )
    )
private func addStorage() {
    try! dataStack.addStorageAndWait(InMemoryStore())
  }
in  DatabaseFacade
final class DatabaseFacade {
  static let sharedInstance = DatabaseFacade()
  let dataStack = RouterHelpers.appDelegate.dataStack

...
we use proceedMessagesList after getting messages from server.
// MARK: - Messages
    func proceedMessagesList(_ reply: MessageListReplyForDatabase) {
        
        dataStack.perform(
            asynchronous: { [weak self] transaction -> Void in
                
                guard let self = self else {
                    return
                }
                
                let existingChat = try self.getChatBy(
                    id: reply.interactionId,
                    with: transaction)
                
                let updatedMessages = reply.updatedList.filter {
                    if $0.isChecklistMessage {
                        return $0.interactionId != $0.nestedChatInfo?.nestedInteractionId
                    } else {
                        return true
                    }
                }
                existingChat?.updateMessages(
                        from: updatedMessages,
                        in: transaction)
                ...
            },
            completion: { result in
                if case .success = result {
                    Logger.log("[DatabaseFacade] proceedMessagesList")
                }
            }
        )
    }
  }
some of ChatStoreObject
import CoreStore
import Foundation

final class ChatStoreObject: CoreStoreObject, ImportableUniqueObject {
    
    @Field.Stored("id")
    private (set) var id = ""
    
    @Field.Relationship("messages", inverse: \.$chat)
    private var messages: [MessageStoreObject]
    
    // MARK: ImportableObject
    
    typealias ImportSource = ChatPlainObject
    
    func didInsert(from source: ImportSource, in transaction: BaseDataTransaction) throws {
        try update(from: source, in: transaction)
    }
    
    // MARK: ImportableUniqueObject
    
    typealias UniqueIDType = String
    
    static let uniqueIDKeyPath = String(keyPath: \ChatStoreObject.$id)
    
    var uniqueIDValue: UniqueIDType {
        
        get { self.id }
        set { self.id = newValue }
    }
    
    static func uniqueID(from source: ImportSource, in transaction: BaseDataTransaction) throws -> UniqueIDType? {
        source.id
    }
    
    func update(from source: ImportSource, in transaction: BaseDataTransaction) throws {
        
        id = source.id
        ...
    }
    
    func updateMessages(from source: [MessagePlainObject], in transaction: BaseDataTransaction) {
        guard let messages = try? transaction.importUniqueObjects(
            Into<MessageStoreObject>(),
            sourceArray: source) else {
            return
        }
        
        self.messages.append(contentsOf: messages)
        updatedDate = Date()
    }
}
in ChatViewController setMessagesMonitor(), use in viewDidLoad()
extension ChatViewController {
    
    func setMessagesMonitor() -> ListMonitor<MessageStoreObject> {
               
        let whereClause: Where<MessageStoreObject>
        
        if isThread {
            whereClause = (
                \.$chatIdForThreadWhereClauseForPublisher == currentChatid &&
                 \.$isCallStatusCalling == false)
        } else {
            whereClause = (
                \.$chatIdForWhereClauseForPublisher == currentChatid &&
                 \.$isCallStatusCalling == false)
        }
        
        let messagesMonitor = DatabaseFacade.sharedInstance.dataStack.monitorSectionedList(
            From<MessageStoreObject>()
                .sectionBy(\.$sentTimeInterval)
                .where(whereClause)
                .orderBy(.ascending(\.$sentTimeInterval))
                .tweak { $0.fetchBatchSize = 20 }
        )
        
        return messagesMonitor
    }
Originally created by @tmbiOS on GitHub (Mar 29, 2023). Hi, John! @JohnEstropia Thank you for you awesome library. We use it in chat app with MessageKit. The problem appears when we migrated from 8.1.0 to 9.0.0 - collectionview starts freeze when scrolling. There is no such problem in the old version 8.1.0. Please help, what we should check? Thanks. Some peaces of code. ```swift in AppDelegate: let dataStack = DataStack( CoreStoreSchema( modelVersion: "V1", entities: [ Entity<CategoryStoreObject>("CategoryStoreObject"), Entity<ChatStoreObject>("ChatStoreObject"), Entity<MessageStoreObject>("MessageStoreObject"), Entity<ProfileStoreObject>("ProfileStoreObject") ] ) ) private func addStorage() { try! dataStack.addStorageAndWait(InMemoryStore()) } ``` ```swift in DatabaseFacade final class DatabaseFacade { static let sharedInstance = DatabaseFacade() let dataStack = RouterHelpers.appDelegate.dataStack ... we use proceedMessagesList after getting messages from server. // MARK: - Messages func proceedMessagesList(_ reply: MessageListReplyForDatabase) { dataStack.perform( asynchronous: { [weak self] transaction -> Void in guard let self = self else { return } let existingChat = try self.getChatBy( id: reply.interactionId, with: transaction) let updatedMessages = reply.updatedList.filter { if $0.isChecklistMessage { return $0.interactionId != $0.nestedChatInfo?.nestedInteractionId } else { return true } } existingChat?.updateMessages( from: updatedMessages, in: transaction) ... }, completion: { result in if case .success = result { Logger.log("[DatabaseFacade] proceedMessagesList") } } ) } } ``` ```swift some of ChatStoreObject import CoreStore import Foundation final class ChatStoreObject: CoreStoreObject, ImportableUniqueObject { @Field.Stored("id") private (set) var id = "" @Field.Relationship("messages", inverse: \.$chat) private var messages: [MessageStoreObject] // MARK: ImportableObject typealias ImportSource = ChatPlainObject func didInsert(from source: ImportSource, in transaction: BaseDataTransaction) throws { try update(from: source, in: transaction) } // MARK: ImportableUniqueObject typealias UniqueIDType = String static let uniqueIDKeyPath = String(keyPath: \ChatStoreObject.$id) var uniqueIDValue: UniqueIDType { get { self.id } set { self.id = newValue } } static func uniqueID(from source: ImportSource, in transaction: BaseDataTransaction) throws -> UniqueIDType? { source.id } func update(from source: ImportSource, in transaction: BaseDataTransaction) throws { id = source.id ... } func updateMessages(from source: [MessagePlainObject], in transaction: BaseDataTransaction) { guard let messages = try? transaction.importUniqueObjects( Into<MessageStoreObject>(), sourceArray: source) else { return } self.messages.append(contentsOf: messages) updatedDate = Date() } } ``` ```swift in ChatViewController setMessagesMonitor(), use in viewDidLoad() extension ChatViewController { func setMessagesMonitor() -> ListMonitor<MessageStoreObject> { let whereClause: Where<MessageStoreObject> if isThread { whereClause = ( \.$chatIdForThreadWhereClauseForPublisher == currentChatid && \.$isCallStatusCalling == false) } else { whereClause = ( \.$chatIdForWhereClauseForPublisher == currentChatid && \.$isCallStatusCalling == false) } let messagesMonitor = DatabaseFacade.sharedInstance.dataStack.monitorSectionedList( From<MessageStoreObject>() .sectionBy(\.$sentTimeInterval) .where(whereClause) .orderBy(.ascending(\.$sentTimeInterval)) .tweak { $0.fetchBatchSize = 20 } ) return messagesMonitor } ```
adam closed this issue 2025-12-29 15:31:06 +01:00
Author
Owner

@JohnEstropia commented on GitHub (Mar 30, 2023):

(edited your comment for syntax highlighting)

There's nothing that stands out in your code above, so I'd need more information. Do you know at which code points the app freezes?

@JohnEstropia commented on GitHub (Mar 30, 2023): (edited your comment for syntax highlighting) There's nothing that stands out in your code above, so I'd need more information. Do you know at which code points the app freezes?
Author
Owner

@tmbiOS commented on GitHub (Apr 5, 2023):

Hi, John! @JohnEstropia
I've made small videos with the same code and two versions of the library.
https://drive.google.com/file/d/1l38BpariNpatZBXkTyhzmu7U8mHPs0iD/view?usp=share_link (8.1.0)
https://drive.google.com/file/d/1_EsyngeomeDDIh41I8oF7fBaxaF0HSww/view?usp=share_link (9.0.0)
The app freezes when scrolling, we got all messages before start scrolling. We have 'Message' model with more than 30 properties and use this Object in the cell.
In what part of the library should I make breakpoints or NSLog for investigation the problem? Thanks

@tmbiOS commented on GitHub (Apr 5, 2023): Hi, John! @JohnEstropia I've made small videos with the same code and two versions of the library. https://drive.google.com/file/d/1l38BpariNpatZBXkTyhzmu7U8mHPs0iD/view?usp=share_link (8.1.0) https://drive.google.com/file/d/1_EsyngeomeDDIh41I8oF7fBaxaF0HSww/view?usp=share_link (9.0.0) The app freezes when scrolling, we got all messages before start scrolling. We have 'Message' model with more than 30 properties and use this Object in the cell. In what part of the library should I make breakpoints or NSLog for investigation the problem? Thanks
Author
Owner

@JohnEstropia commented on GitHub (Apr 6, 2023):

I see, so it's not freezing but the scrolling does stutter. Can you try to use instruments to find what's likely taking up the render cycles?

You can check the release contents for 9.0.0 here; there weren't any structural changes that should directly cause this, so it would help if you can provide more context on your side of the migration.

@JohnEstropia commented on GitHub (Apr 6, 2023): I see, so it's not freezing but the scrolling does stutter. Can you try to use instruments to find what's likely taking up the render cycles? You can check the release contents for 9.0.0 [here](https://github.com/JohnEstropia/CoreStore/releases/tag/9.0.0); there weren't any structural changes that should directly cause this, so it would help if you can provide more context on your side of the migration.
Author
Owner

@tmbiOS commented on GitHub (Apr 28, 2023):

I see, so it's not freezing but the scrolling does stutter. Can you try to use instruments to find what's likely taking up the render cycles?

You can check the release contents for 9.0.0 here; there weren't any structural changes that should directly cause this, so it would help if you can provide more context on your side of the migration.

Yes, there was the problem with UI, thanks. This issue should be closed.

@tmbiOS commented on GitHub (Apr 28, 2023): > I see, so it's not freezing but the scrolling does stutter. Can you try to use instruments to find what's likely taking up the render cycles? > > You can check the release contents for 9.0.0 [here](https://github.com/JohnEstropia/CoreStore/releases/tag/9.0.0); there weren't any structural changes that should directly cause this, so it would help if you can provide more context on your side of the migration. Yes, there was the problem with UI, thanks. This issue should be closed.
Author
Owner

@tmbiOS commented on GitHub (Sep 20, 2023):

There was the problem with UI

@tmbiOS commented on GitHub (Sep 20, 2023): There was the problem with UI
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: starred/CoreStore#407