autoreleasepools and SwiftUI

I am experimenting with using Swift and SwiftUI for processing genomics data. The hallmark of genomics data is very large data files. Common formats are text files known as fasta and fastq file formats. For the human genome, these files contain more than 40 million lines of text.

Being able to write code that can read such large files line by line is essential. After some trial and error and much reading I finally understand Automatic Reference Counting and the importance of using an autoreleasepool to prevent memory from being consumed.

I typically read such large files in a background thread and asynchronously update the UI (written in SwiftUI) using DispatchQueue.main.async by setting properties in my ContentView. This works fine. However, as I reach 40 million lines of text, updating the UI consumes memory without releasing it.

I have tried to incorporate autoreleasepools in the ContentView using the usual autoreleasepool { ... } syntax. However, within such constructs as VStacks, I encounter errors such as "Type () cannot conform to 'View"; only struct/enum/class types can conform to protocols"

It seems that autorelease pools do not play well with SwiftUI. What guidance is there for effectively managing memory with SwiftUI?

Thank you.
UPDATE:

I believe I found what was consuming memory as I updated the UI...

I have a View that contains a Text object that displays the number of sequences read from a file of DNA sequences as well as a List of sequence names. These files are typically very large because each individual sequence can consist of thousands to millions of nucleotides. However, the number of sequences in a file can be relatively small and manageable. My goal is to read these files and display the number of sequences as well as a list of the sequence names and statistics about each sequence (but not all the nucleotides because that is too much data).

I update the Text object periodically by setting a property that I call sequenceCount. This property is a member of the following class:

class ObservableSequences: ObservableObject {
    @Published var sequenceCount: String? = "0"
    @Published var sequenceData: [SequenceData] = []
}

sequenceCount contains the number of sequences read from the file while sequenceData contains information about each sequence in the file. I periodically update sequenceCount from a background thread that is reading the file. I do this to keep the user informed about the progress being made processing the file.

I have a master/detail UI. My master View is declared as follows:

struct MasterView: View {
    @ObservedObject public var observableSequences = ObservableSequences()
    var body: some View {
        VStack {
            Text("Number of Lines: " + observableSequences.sequenceCount!)
            List(self.observableSequences.sequenceData, id: \.self) {sequenceData in
                NavigationLink(destination: DetailView(sequence: sequenceData.sequence)) {
                    Text(sequenceData.sequence)
                }.background(Color.red)
            }
        }
    }
}

For reasons that I don't remember, I had originally written this View as follows:

struct MasterView: View {
    @ObservedObject public var observableSequences = ObservableSequences()
    var body: some View {
        VStack {
            Text("Number of Lines: " + observableSequences.sequenceCount!)
            List(self.observableSequences.sequenceData, id: \.self) {sequenceData in
                NavigationLink(destination: DetailView(sequence: sequenceData.sequence)) {
                    Text(sequenceData.sequence)
                }.background(Color.red)
            }.id(UUID()) <------------------------NOTE THE USE OF .id
        }
    }
}

When I removed .id(UUID()), memory no longer grew out of control and remained stable.

It seems that each time I updated sequenceCount, the UI would be recreated (as I would expect). And each List that is created got a new .id. My guess (and it is only a guess) is that each new List was being retained in memory. Without the unique id, a new List is either not created or the previous List is being disposed of and not retained in memory.

In any case, my code is now behaving nicely even though I am reading exceptionally large files.

autoreleasepools and SwiftUI
 
 
Q