1

I have severe UI hang issues whenever my sync worker is running. The app experiences:

Screen navigation freezes Scroll lag and stuttering Unresponsive UI during data synchronization

The root cause is Realm database read/write operations blocking the main thread during a sync process that involves 99+ sequential database operations. Environment

  • iOS: 16.0+ (issue more prominent on iOS 26)
  • Swift: 5.x
  • Framework: SwiftUI
  • RealmSwift: 20.0.0

Current Behavior

class WorkManager {
    func syncChanges() async {
        await uploadData()    // Uploads local data to server
        await downloadData()  // 51 sync operations with extensive DB reads/writes
    }
}

During this sync:

  • User cannot scroll smoothly
  • Navigation transitions freeze
  • App appears hung/unresponsive
  • UI becomes usable only after sync completes
3
  • Normally you wouldn't have async funcs in a class since class is for managing mutable state and async funcs can be re-entered which would corrupt the state. So it's a sign you have an architectural problem. Try removing async and using Task inside the func (protected by an isAlreadySyncing flag) you also need to change class to actor. Or simply change class to struct. Commented Nov 26 at 14:22
  • But sounds to me your main problem is the code for syncing is defined within MainActor instead of somewhere else. Commented Nov 26 at 14:30
  • If i try to move Realm class to background then the Realm is accessed from incorrect thread error is thrown. What feels to me is that write operations should be in background priority thread. and fetching data should be in main actor? Commented Nov 27 at 6:19

1 Answer 1

0

Looks like your issue might be that you're firing off a bunch of tiny operations one after another, and Realm keeps locking/unlocking the file every second because of that, which is why you’re getting the UI lag. Try these two options.

A) instead of doing 50 small write transactions, combine everything into one big one.

let realm = try Realm()

try realm.write {
    for op in ops {
        runOperation(op, in: realm)
    }
}

Just make sure you’re not doing this on the main thread and run it inside a Task on a background priority.

b) if you’re processing a lot of data and one huge transaction makes things even heavier, then split the array into small chunks and process each chunk separately. Each chunk becomes its own batch transaction. That way you get a series of short operations instead of one large.

let realm = try Realm()

for chunk in items.chunked(into: 20) {
    try realm.write {
        chunk.forEach { realm.add($0, update: .modified) }
    }
}

The idea behind both solutions is the same, reduce the number of moments where Realm locks the file and makes your UI wait. Try both approaches, in most cases one of them noticeably reduces the lag.

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.