Performance issues when using CoreData as messages dataSource
- Dominant language
- Swift
- Stars
- 4.6k
- Forks
- 588
- PR merge metrics
- No merged PRs in 30d
Description
Hi!
I'm using `CoreData` to store messages for chat room. When users taps on specific chat cell, app fetches messages for this chat from `CoreData` and create `ChatItemProtocol` items, which is then added to `dataSource`. It looks like this:
```swift
func messagesForCurrentChat(chat_id: String) -> [ChatItemProtocol] {
var messages = [ChatItemProtocol]()
let fetchRequest: NSFetchRequest = Message.fetchRequest()
let predicate = NSPredicate(format: "chat_id like %@", chat_id)
let sd = NSSortDescriptor(key: "timestamp", ascending: true)
let sortDescriptors = [sd]
fetchRequest.predicate = predicate
fetchRequest.sortDescriptors = sortDescriptors
fetchRequest.fetchBatchSize = 10
let fetchedResultsController = NSFetchedResultsController(fetchRequest: fetchRequest,
managedObjectContext: self.coreDataStack.managedContext,
sectionNameKeyPath: nil,
cacheName: nil)
do {
try fetchedResultsController.performFetch()
for object in fetchedResultsController.fetchedObjects! {
if !object.isMedia {
let textMessage = createTextMessageModel(object.id!, sender: object.sender!, text: object.textContent!, date: object.timestamp! as Date, isIncoming: object.incoming, status: Int(object.status))
messages.append(textMessage)
} else {
if let url = object.mediaContent {
let photoMessage = createPhotoMessageModel(object.id!, sender: object.sender!, date: object.timestamp as! Date, image: nil, imageUrl: url, size: CGSize(width: 300.0, height: 300.0), isIncoming: object.incoming, status: Int(object.status))
messages.append(photoMessage)
}
}
}
} catch let error as NSError {
print("Fetching error: \(error), \(error.userInfo)")
}
return messages
}
```
So, then in `prepare(for segue)` in ChatListViewController:
```swift
class ChatListViewController: UIViewController {
...
...
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == "ChatSegue" {
let controller = segue.destination as! ChatViewController
controller.selectedChat = self.selectedChat
let messagesForChat = messagesForCurrentChat(chat_id: self.selectedChat.uid!)
let dataSource = SlidingDataSource(messages: messagesForChat, pageSize: 50)
controller.dataSource = dataSource
}
}
```
And when I have more then 100 messages in chat, it looks some time to open chat with messages (if compare to ChattoApp when opening 10000 messages chat). So, my question is, how to optimise this chat opening issues?
Maybe I need to fetch not all messages for this chat, but only 50 (the same as `pageSize` in `SlidingDataSource`), and when I scroll up asynchronously fetch messages from `CoreData` and add them to `dataSource`? But is it possible to dynamically add messages to `dataSource` to the top?
Anyway, thanks for any help, this bug is tormenting me for few month :)
Contributor guide
Research direction
Start with messagesForCurrentChat in ChatListViewController and trace how its CoreData results are passed to SlidingDataSource and ChatViewController during prepare(for:). Reproduce the delay with a chat containing more than 100 messages, then define and validate an agreed loading behavior, including whether messages can be added at the top while scrolling.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- swift
- Domain
- mobile, performance
- Issue type
- Bug
- Difficulty
- 5/5
- Estimated time
- Over a week
- Activity status
- Stale
- Clarity
- Needs clarification
- Newbie friendliness
- 20/100