Post

Replies

Boosts

Views

Activity

Reply to SwiftUI Lists
Here is an experiment I did... TextItem is the item I want to display in a list. For grins I gave it a property called tapped. TextItemView is a View for presenting a TextItem. Finally, there is TextListView for presenting the list of TextItemViews. This code as written does display the list of items. And the onTapGesture is fired whenever an item is clicked. However, the background color of the TextItemView does not change. Why not? Because the view is not refreshed. I force a refresh of the view by changing the refresh state variable in TextListView. However, that has no effect. Why is this the case? Turns out that the refresh state variable is not used in the body of the TextListView. If I simply add a Text struct to the VStack to display refresh, then the TextListView is updated whenever refresh is changed in the onTapGesture. That said, this is not a satisfactory solution. I can click on items and change toggle their background color with each click. However, this needs to be coordinated with all the other items in the list. To do this I have to write code to turn off of the tapped state of each item and then set the selected items tapped state to true. import SwiftUI class TextItem: Identifiable {     var id = UUID()     var name: String = ""     var tapped = false     init(name: String) {         self.name = name     } } struct TextItemView: View {     var item: TextItem     var body: some View {         Text("\(item.name)")     } } struct TextListView: View {     var Items: [TextItem] = []     @State private var refresh = 0;     var body: some View {         VStack {         List(Items) {item in             if item.tapped {                 TextItemView(item: item)                     .onTapGesture {                         print("tap")                         item.tapped.toggle()                         self.refresh += 1                     }.background(Color.blue)             } else {                 TextItemView(item: item)                     .onTapGesture {                         print("tap")                         item.tapped.toggle()                         self.refresh += 1                     }.background(Color.white)             }         }     } }
Dec ’20
Reply to How to call the C function, getline, from Swift?
I was able to simplify the call to getline a bit with the following code. What makes the call a bit tricky is the first argument which is a pointer to a pointer. I find that I can use an ampersand on standard types such as Int. For example, if I declare linecapp to be an integer, then passing &linecapp causing linecapp to be encapsulated within a UnsafeMutablePoint. Similarly, if I declare line to be an array, then passing &line encapsulates the array in an UnsafeMutablePointer. Notice how I use &line when initializing linep, the pointer to line. And notice how I pass &linecapp as the second parameter to linecapp. At the moment I don't see any other simplifications that I can perform on the code. // declare an array to hold an incoming line var line = Array<Int8>(repeating: 0, count: 200) // declare a pointer to the line let linep = UnsafeMutablePointer<UnsafeMutablePointer<Int8>?>.allocate(capacity: 1) linep.initialize(to: &line) // specify the size of the line var linecapp = 200 // open the file let fp = fopen(fileName, "r") // loop to read the file while (true) { let r = getline(linep, &linecapp, fp) if r == -1 { break } // do something with the line // convert the line to a string let str = String(cString: line) // print the string print(str) } linep.deinitialize(count: 1) linep.deallocate
Oct ’20
Reply to How to call the C function, getline, from Swift?
I was able to simplify the call to getline a bit with the following code. What makes the call a bit tricky is the first argument which is a pointer to a pointer. I find that I can use an ampersand on standard types such as Int. For example, if I declare linecapp to be an integer, then passing &linecapp causing linecapp to be encapsulated within a UnsafeMutablePoint. Similarly, if I declare line to be an array, then passing &line encapsulates the array in an UnsafeMutablePointer. Notice how I use &line when initializing linep, the pointer to line. And notice how I pass &linecapp as the second parameter to linecapp. At the moment I don't see any other simplifications that I can perform on the code. // declare an array to hold an incoming line var line = Array<Int8>(repeating: 0, count: 200) // declare a pointer to the line let linep = UnsafeMutablePointer<UnsafeMutablePointer<Int8>?>.allocate(capacity: 1) linep.initialize(to: &line) // specify the size of the line var linecapp = 200 // open the file let fp = fopen(fileName, "r") // loop to read the file while (true) { let r = getline(linep, &linecapp, fp) if r == -1 { break } // do something with the line // convert the line to a string let str = String(cString: line) // print the string print(str) } linep.deinitialize(count: 1) linep.deallocate
Oct ’20
Reply to Combine Publisher + SwiftUI = MemoryLeak
I have some code that is very similar. In my case I am reading a large file in a background thread and updating the published property (rather than using a timer). But I get the same result - a memory leak. After about 400 updates my memory usage doubles. I've tried using autoreleasepools in my ContentView. However, they don't seem to have any effect.
Sep ’20
Reply to autoreleasepools and SwiftUI
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.
Sep ’20