swiftswiftuitextset

(1 week into learning Swift) Is it ok to compute(?) inside the body?


import SwiftUI

struct ContentView: View {
    
    @State private var fiveNumbers: Set<Int> = []
    @State private var twoNumbers: Set<Int> = []
    // there has to be a better way to copy a Set instead of making it a string like this. it includes brackets too....
    // options: remove all [] from string OR find another way to get the numbers into the boxes without being a string
    @State private var fiveSentence = ""
    @State private var twoSentence = ""
    
    var body: some View {
        NavigationStack {
            Form {
                Button("Faz o meu Euromilhões") {
                    fiveNumbers.removeAll()
                    twoNumbers.removeAll()
                    
                    while fiveNumbers.count < 5 {
                        let newRandomNumber = Int.random(in: 1...50)
                            fiveNumbers.insert(newRandomNumber)
                    }
                    let sortedNumbers = fiveNumbers.sorted()
                    fiveSentence = "\(sortedNumbers)"
                    
                    while twoNumbers.count < 2 {
                        let newRandomNumber = Int.random(in: 1...12)
                            twoNumbers.insert(newRandomNumber)
                    }
                    let sortedTwoNumbers = twoNumbers.sorted()
                    twoSentence = "\(sortedTwoNumbers)"
                }
                
                Section("Números") {
                    Text(fiveSentence)
                }
                Section("Estrelas") {
                    Text(twoSentence)
                }
            }
            .navigationTitle("Euromilhões")
            .toolbar {
                if !fiveNumbers.isEmpty {
                    Button("Limpar") {
                        fiveSentence.removeAll()
                        twoSentence.removeAll()
                        fiveNumbers.removeAll()
                        twoNumbers.removeAll()
                    }
                }
            }
        }
    }
}

Let me preface this by saying I have no experience in coding and I'm an absolute beginner. This is a throwaway project I'm tinkering with after 1 week of 100 days of Swift.

- Q1: Is this ok, or should I compute (not sure if this is the correct term?) outside of the body for the button:

Button("Faz o meu Euromilhões")

Q2: I tried to be "smart" and use

  • @State private var fiveNumbers: Set<Int> = []

instead of

  • @State private var fiveNumbers: [Int] = []

to avoid having to write more code to not get repeated numbers. if !fiveNumbers.contain(newRandomNumber) { fiveNumbers.append(newRandomNumber) }

but how can I get the array into Text without brackets?

Thank you so much for your time and patience!


Solution

  • Q1: The way you are doing it is formally “okay”. It does not violate the way SwiftUI works. You are not really computing inside the body of ContentView. Instead, you are passing a “closure” (a function) to the Button. The Button saves the closure and runs it later, when it (the Button) is tapped. That’s when the computation happens.

    The way you are doing it is also “okay” for a toy project, where you don’t intend to keep the code around for a long time and you don’t intend to write test cases.

    If this were a serious project, you would want to factor that code out into a standalone function so that you could write tests for it.

    Q2: Here’s one way to turn a Set<Int> into a Text:

            Text(
                fiveNumbers
                    .sorted()
                    .formatted(ListFormatStyle(memberStyle: .number))
            )
    

    Here’s another way:

            Text(
                fiveNumbers
                    .sorted()
                    .map { "\($0)"}
                    .joined(separator: ", ")
            )