Displaying a Set in a View

The function:

browseResultsChangedHandler: ((_ newResults: Set<NWBrowser.Result>, _ changes: Set<NWBrowser.Result.Change>) -> Void)?

returns two Set type parameters. There is data in each element of these sets I need to display in a view. What is the best way to convert these sets to an array that can be iterated in a "ForEach" statement so they can be displayed in a View?

When I attempt to do it on a set directly I get the error:

Cannot convert value of type 'Set<NWBrowser.Result>' to expected argument type 'Range<Int>'

I would create a computed var that creates the array from the set.

var newResultsArray: [NWBrowser.Result] {
  Array(newResults)
}

Take care of the order: Set is not ordered, you may have to sort the array with a .sort modifier

You definitely want to sort the results. When you sort, use localizedStandardCompare(_:) so that your results match other service lists we display (such as the Finder).

How you sort depends on how you’re browsing:

  • If you browse hierarchically — that is, you browse for domains, let the user choose a domain, and then browse for services within that domain — you want to maintain separate service lists for each domain.

  • If you browse just the local domain, you will only get results in that domain so you can ignore the domain value of each result and simply display a flat list.

  • If you browse in the default domains, by passing in nil or the empty string, you have to decide whether you want to show results hierarchically or not. This gets kinda complicated because in most cases you won’t get results from multiple domains so it’s best to display a flat list of services. However, in the case where you do get services from multiple domains you have to make a choice as to whether to:

    • Transition to a hierarchical UI

    • Continue using a flat list

    In the second case you might encounter multiple services with the same name but in different domains, something you’ll need a represent in your UI.

Share and Enjoy

Quinn “The Eskimo!” @ Developer Technical Support @ Apple
let myEmail = "eskimo" + "1" + "@" + "apple.com"

Thank you for your reply. In my case what needs to be enumerated are four iPhones connected to a MacStudio by means of Lightning Cable. I am attempting to enumerate these to establish communications with software also written by me in the iPhones.

I did the conversion you recommended. But when I attempt to use my equivalent of your "newResultsArray" in a View's ForEach statement I find that something is lost in the conversion. When I attempt to use my equivalent, which in my code is the results member of the SSH_Browser class (code below), I get an error in the View. What was lost? What needs to be done to get the print function to accept it?

The code, and the error message in comments:

struct ContentView: View {
    @StateObject var sshBrowser = SSH_Browser()
    var body: some View {
        VStack {
            ForEach( sshBrowser.results, id:\.hashValue ) { result in
                print("result ", result )  // Red underline under the first character of "print(...". The error: "No exact matches in reference to static method 'buildExpression'"
            }
        }
        .padding()
    }
}
class SSH_Browser: ObservableObject {    
    var browser: NWBrowser!
    @Published var results: [NWBrowser.Result] = []
    
    init() {
        let bonjourTCP = NWBrowser.Descriptor.bonjour(type: "_ssh._tcp" , domain: nil)
        let bonjourParms = NWParameters.init()
        browser = NWBrowser(for: bonjourTCP, using: bonjourParms)
        
        // This change event handler code executes when available devices change.
        browser.browseResultsChangedHandler = { ( results, changes ) in
            for result in results {
                print("result ", result ) // No error here. The "result" Set element is accepted.
                if case .service(let service) = result.endpoint {
                    print("bonjourA ", service.name)
                }
            }
            self.results = Array( results ) // Something is lost here, for when used in the View the print() function does not accept the self.results array elements.
        }
        browser.start(queue: DispatchQueue.main)
    }    
}
Displaying a Set in a View
 
 
Q