0

i am working on an SwiftUI app, which needs to perform multiple coreData comparisons between two tables. The Problem is, when i do the comparison, my app randomly crashes.. i need to keep a close eye on the performance as well, that is why i use xCode instruments to inspect all the necessary parts.. with using the leak tool from instruments i've noticed that in fact leaks are happening while i do those comparisons.

xcode instr leaks ss

i've already debugged it down to the fact that those leaks only happen when i do the comparison between those two tables.

Here's an demo project, to see this issue in action

contentView:

struct ContentView: View {
 @Environment(\.modelContext) private var modelContext
 @Query private var items: [Item]
 
 var body: some View {
 VStack {
 Button(action: {
 Task { await testImport() }
 }, label: {
 Text("Import")
 })
 }
 }
}

here 's the function:


extension ContentView {
 func testImport() async {
 // cleanup
 do {
 print("starting cleanup...")
 do {
 try modelContext.delete(model: Item.self)
 print("cleanup: table LocalAsset truncated")
 } catch {
 print("Failed to clear all LocalAsset data.")
 }
 }
 
 // create dummy data:
 var dummyArray: [Int] = []
 
 for i in 0...1300 {
 dummyArray.append(i)
 }
 
 let actorX = testActor(modelContainer: modelContext.container)
 await actorX.saveAssets(with: dummyArray)
 
 print("Checkpoint")
 
 }
}

My Actor:


actor testActor {
 var modelContainer: ModelContainer
 
 init(modelContainer: ModelContainer) {
 self.modelContainer = modelContainer
 }
 
 func saveAssets(with array: [Int]) {
 let modelContext = ModelContext(modelContainer)
 
 let batchSize = 1000
 let totalObjects = array.count
 var currentIndex = 0
 while currentIndex < totalObjects {
 let remainingCount = min(batchSize, totalObjects - currentIndex)
 
 for i in 0..<remainingCount {
 
 let foo = array[currentIndex + i]
 let newItem = Item(timestamp: Date(), dummyInt: foo)
 modelContext.insert(newItem)
 }
 
 do {
 try modelContext.save()
 } catch {
 print("Error saving context: \(error)")
 }
 currentIndex += remainingCount
 }
 print("wrote \(currentIndex) new rows to table")
 }
}

i do think that those issues come from the fact that i create a seperated context inside "saveAssets"...

what am i missing here? i'm debugging this situation for weeks already, did build the App from scratch multiple times, to get an understanding what and why this is happening in the first place... but i seem to make no ground on this..unfortunately :/ is this because of SwiftData, or do i miss some fundamentally understanding of how things are suposed to be done here?

i am still pretty new to SwiftUI and SwiftData but got some experience with Swift and CoreData.. i've found this script on hackingWithSwift, which helped to import a large amount of data into SwiftData in a reasonable amount of time:

insertLargeAmountsOfDataEfficiently

if necessary i can of course show you my real function as well.. i hope u got any ideas how to solve this leak issue, and how to work with background contexts in SwiftData because i got pretty much stuck here :/

asked Feb 24, 2024 at 9:40
7
  • This is not reproducible when adding your code to a new SwifttUI/SwiftData project. Commented Feb 24, 2024 at 17:23
  • i will build a debug project to recreate that behavior asap, and will update the top post.. Commented Feb 24, 2024 at 18:41
  • updated..could it be that the actor now has a strong reference to the container, and this allocated memory does not get released anymore? Commented Feb 25, 2024 at 8:08
  • 1
    I can now reproduce the issue. Commented Feb 25, 2024 at 8:14
  • 1
    Two observations, moving the saveAssets out of the actor so it runs on the main actor produces the same leak and updating the moved functions so it used the main context instead of creating a new one produces no leaks. So it's clearly related to creating a new context so is the issue within the ModelContainer perhaps? Another thing, I ran my own app and checked for leaks and I have similar leaks for my actor that conforms to ModalActor. It leaks during init, that is when the model context instance is created. Commented Feb 25, 2024 at 8:48

0

Know someone who can answer? Share a link to this question via email, Twitter, or Facebook.

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

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.