When developing a master/detail application, the usual scenario is to have a list as a master view. The user selects an item in the list and the details appear in a detail view.
In my application, a user chooses a menu option to read items from a text file and to populate the list in the master view. This works well and when the user selects an item in the list, the details appear in the detail view.
However, initially, no item is selected. As a consequence there is no detail view. The entire window is occupied by the list in the master view. I would like to at least show an empty detail view when no item is selected in the master view. However, I haven't figured out how to do this.
Any thoughts?
Post
Replies
Boosts
Views
Activity
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.
This post isn't a question. Instead I am posting an example in the hope that doing so will help others. My need was to read a large text file (gigabytes in size) a line at a time. I created a bridging header to call the C getline function. Calling get line is interesting because it relies on pointers. Here is how it works.
// Author: David Cox
// Example to illustrate how to call the C function
// getline from Swift
//
// This is the definition of getline as viewed from
// Swift:
//
// public func getline(_ __linep:
// UnsafeMutablePointer<UnsafeMutablePointer<Int8>?>!,
// _ __linecapp: UnsafeMutablePointer<Int>!,
// _ __stream: UnsafeMutablePointer<FILE>!) -> Int
//
// readFile will call getline to read a file
// line-by-line
func readFile(fileName: String) {
// In this example, I am creating a buffer that
// getline will fill with characters.
// Technically, I don't have to do this.
// getline will accept a NULL pointer and will
// allocate memory for the incoming line.
// However, that approach requires that the
// memory be freed by the user program.
// I find that creating the buffer in advance
// is simpler to understand.
// So, here is the first step. Create a pointer
// and point it to an area of memory.
// Think of this memory as a C array.
// In this example, the area of memory will
// have a capacity of 200 Int8 elements
// and the pointer will be called buffer:
let buffer =
UnsafeMutablePointer<Int8>.allocate(capacity: 200)
// Initialize the memory. In this case I am
// initializing the memory to 200 zeros:
buffer.initialize(repeating: 0, count: 200)
// Next, create another UnsafeMutablePointer
// and point it to the buffer.
// Because buffer is also an
// UnsafeMutablePointer the type of this
// pointer will be UnsafeMutablePointer
// This pointer will point to an area of memory
// containing 1 element.
let bufferPtr =
UnsafeMutablePointer<UnsafeMutablePointer<Int8>?>.
allocate(capacity: 1)
// Initialize this area of memory to hold buffer
// (which is an UnsafeMutablePointer)
bufferPtr.initialize(to: buffer)
// Create another pointer to an area of
// memory that will hold the size of the buffer
// The size is an stored as 1 Int. Hence, the
// capacity is 1.
let bufferSize =
UnsafeMutablePointer<Int>.allocate(capacity: 1)
bufferSize.initialize(to: 200)
// Now we are ready to open the file
let fp = fopen(fileName, "r")
// loop to read the file
while (true) {
let r = getline(bufferPtr, bufferSize, fp)
if r == -1 {
break
}
// convert the buffer contents to a string
let line = String(cString: bufferPtr.pointee!)
// do something with the line
print(line)
}
// deinitialize the pointers
bufferPtr.deinitialize(count: 1)
buffer.deinitialize(count: 200)
// deallocate the pointers
bufferPtr.deallocate()
buffer.deallocate()
}
SwiftUI uses a concept referred to as "source of truth." When the source of truth changes, the UI updates to reflect the change. This works fine for small to moderate amounts of data. However, some domains such as genomics work with very large data sets that predominantly reside on disk or network storage. The UI is, at best, a snapshot of a small amount of that data.
Since "source of truth" cannot be an entire genomic data set, what would be a good approach for connecting a SwiftUI interface to such a data set?
It seems to me that the "source of truth" must include functionality that retrieves some subset of the larger data set. As an example, the "source of truth" might page forwards or backwards through the larger data set. Thus, the UI might include buttons for paging. As the "source of truth" is updated, those updates are reflected in the UI.
In summary:
large data set <--> source of truth <--> UI
Does this sound reasonable?
I have quite a bit of material about SwiftUI Lists. However, I seem to be lacking information about how to respond to an item being "selected". I put "selected" into quotes because my idea of selecting an item is different from putting a list into selection mode.
For example, in the book "SwiftUI for Masterminds" discusses in Chapter 10 about presenting a selection tool when a List is initialized with the selection attribute. The selection tool presents checkboxes (circles actually) that allow the user to select one or more items in the list. This type of selection is not what I am thinking about.
When I refer to selecting an item I mean tapping or clicking (on a Mac) an item. This action fires an event that the application responds to. This is not necessarily a navigation event. It might be that the appropriate response is send a message to a remote site or to perform a calculation using the item that was tapped or clicked. Thus, the complexity of navigation views need not come into play.
At the moment I don't have satisfactory answers for implementing this kind of behavior. I have found that I can an onTapGesture modifier to each item in the list. However, this seems like a convoluted approach. I really want the behavior to be at the level of the List. The tap or click would be associated with the List rather than with each item in the List.
As I learn more I will update this post. Please feel free to add additional information here. I would like to see this post be a useful resource for everyone.
I have a C++ command line project that was working fine. I installed SDL2-2.28.5.dmg and wanted to experiment using SDL2 in my app. However, after I added the framework to my project XCode would hang whenever I loaded the project. By hang I mean that it would start loading the project and never finish.
I eventually found that I could fix this by opening the xcodeproj file by first selecting Show Package Contents in Finder and then moving project.xcworkspace to trash. After doing so, I could then double click on the xcodeproj file and XCode would then load the project without hanging.
However, even though XCode has loaded the project there is a message at the top that says Indexing Open Quickly Content. It seems to be stuck at about 40%. Also, there is another message at the top that says Loading... with a spinner next to it. My fans are also blowing pretty hard while this is happening.
Now that I have waited several minutes, I see that XCode has made no progress on Indexing Open Quickly Content and is now hung again.
Coming from a Windows development background, it is astounding to me how fragile XCode is.