ios - I got this error trying to create a While loop in swift: Closure containing control flow statement cannot be used with result builder 'ViewBuilder' - TagMerge
3I got this error trying to create a While loop in swift: Closure containing control flow statement cannot be used with result builder 'ViewBuilder'I got this error trying to create a While loop in swift: Closure containing control flow statement cannot be used with result builder 'ViewBuilder'

I got this error trying to create a While loop in swift: Closure containing control flow statement cannot be used with result builder 'ViewBuilder'

Asked 11 months ago
0
3 answers

You aren’t able to use while or for loops in your View. However, since you made realHour, realMinute, and realSecond @State variables, they will update the view anytime they change! Simply removing the while loop works, and the values will update as soon as you press the “Press” button. As written, they only update once, because the time() function uses the same hour, minute, and second values each time. To get that function to work multiple times, you want to either bring the functions inside the function, like this:

func time() {
    realHour = 24 - Calendar.current.component(.hour, from: Date())
    realMinute = 60 - Calendar.current.component(.minute, from: Date())
    realSecond = 60 - Calendar.current.component(.second, from: Date())
}

or make them computed properties, like this:

var hour: Int { Calendar.current.component(.hour, from: Date()) }
var minute: Int { Calendar.current.component(.minute, from: Date()) }
var second: Int { Calendar.current.component(.second, from: Date()) }

I’ve included the full code below.

As was mentioned in the comments, timelineView may be what you want if you want to bypass the “Press” button entirely. I also recommend looking into the timer; it seems like you could remove it entirely (keeping the lines inside), at least with the code you posted.

Here’s the full code that works for me:

import SwiftUI

struct ContentView: View {
    
    var hour: Int { Calendar.current.component(.hour, from: Date()) }
    var minute: Int { Calendar.current.component(.minute, from: Date()) }
    var second: Int { Calendar.current.component(.second, from: Date()) }
    @State var realHour:Int = 0
    @State var realMinute:Int = 0
    @State var realSecond:Int = 0
    @State var isTimeShown:Bool = false
    
    func time() {
        realHour = 24-hour
        realMinute = 60-minute
        realSecond = 60-second
    }
    
    var body: some View {
        ZStack {
            VStack{
                Spacer()
                HStack {
                    if isTimeShown {
                        Text(String(realHour))
                        Text(":")
                        Text(String(realMinute))
                        Text(":")
                        Text(String(realSecond))
                    }
                }
            }.padding(.bottom, 100)
            HStack {
                Button {
                    Timer.scheduledTimer(withTimeInterval: 0, repeats: false) {
                        Timer in
                        time()
                        isTimeShown = true
                    }
                } label: {
                    Text("Press")
                }
            }
            Spacer()
        }
    }
}

struct ContentView_Previews: PreviewProvider {
    static var previews: some View {
        Group {
        ContentView()
        }
    }
}

Source: link

0

This works...
//Function to Trim Integer (Prefix Only)
func integerTrim(integer:Int, trimLength:Int) -> Int {
    var strFromInteger = String(integer)
    var trimmedString = strFromInteger.prefix(trimLength)
    var intFromString = Int(trimmedString) ?? 0
    return intFromString
}

//Declare Input
var inputInt = 12345678910

//Call Function
var result = integerTrim(integer: inputInt, trimLength: 4)

//Print Results
print(inputInt)
print(result)
This doesn't...!
//Function to trim integer prefix or suffix
func integerTrim(integer:Int, type:String, trimLength:Int) -> Int {
    var typeID = type
    //var turnStringToInteger: Int
    if typeID == "P" {
        var turnIntegerToString = String(integer)
        var trimmedString = turnIntegerToString.prefix(trimLength)
        var turnStringToIngeger = Int(trimmedString) ?? 0
    }
    else if typeID == "S" {
        var turnIntegerToString = String(integer)
        var trimmedString = turnIntegerToString.suffix(trimLength)
        var turnStringToIngeger = Int(trimmedString) ?? 0
    }
    return turnStringToInteger
}

//Declare Input
var inputInt = 53737363856453

//Call Function
var result = integerTrim(integer: inputInt, type: "P", trimLength: 4)

//Print Results
print(inputInt)
print(result)
So your real issue is the use of String as the type for type. It would be better to use an enum that expresses exactly what you want:
enum TrimType {
    case prefix, suffix
}

func integerTrim(integer: Int, type: TrimType, trimLength: Int) -> Int {

    let typeID = type
    var turnStringToInteger: Int

    switch typeID {
    case .prefix:
        let turnIntegerToString = String(integer)
        let trimmedString = turnIntegerToString.prefix(trimLength)
        turnStringToInteger = Int(trimmedString) ?? 0
    case .suffix:
        let turnIntegerToString = String(integer)
        let trimmedString = turnIntegerToString.suffix(trimLength)
        turnStringToInteger = Int(trimmedString) ?? 0
    }

    return turnStringToInteger
}
You call it like this:
let result = integerTrim(integer: inputInt, type: .prefix, trimLength: 4)
... after a little refactoring:
func integerTrim(integer: Int, type: TrimType, trimLength: Int) -> Int {

    let turnIntegerToString = String(integer)
    let trimmedString: Substring

    switch type {
    case .prefix:
        trimmedString = turnIntegerToString.prefix(trimLength)
    case .suffix:
        trimmedString = turnIntegerToString.suffix(trimLength)
    }

    return Int(trimmedString) ?? 0

}
There's a few ways to do this. The root of the problem is your turnIntegerToString lifetime is within the braces - and the return is outside the braces.
func integerTrim(integer:Int, type:String, trimLength:Int) -> Int {
    var typeID = type
    var turnStringToInteger: Int = 0
    // If you don't want to assign it to zero (your nil coalesce implies we can) - instead use...
    // var turnStringToInteger: Int! // However - this can crash since your if statement does not cover all situations

    if typeID == "P" {
        var turnIntegerToString = String(integer)
        var trimmedString = turnIntegerToString.prefix(trimLength)
        turnStringToIngeger = Int(trimmedString) ?? 0
    }
    else if typeID == "S" {
        var turnIntegerToString = String(integer)
        var trimmedString = turnIntegerToString.suffix(trimLength)
        turnStringToIngeger = Int(trimmedString) ?? 0
    }
    return turnStringToInteger
}

Source: link

0

This example iterates over an array of cities, also known as a collection in Swift.
let cities = ["Amsterdam", "New York", "San Francisco"]
for city in cities {
    print(city)
}

// Amsterdam
// New York
// San Francisco
This example iterates over a dictionary. Here, it prints out the age of each person.
let ages = ["Antoine": 28, "Jaap": 2, "Jack": 72]
for (name, age) in ages {
    print("\(name) is \(age) years old")
}

// Antoine is 28 years old
// Jaap is 2 years old
// Jack is 72 years old
The following example uses a range to execute the print statement 4 times. Fun fact, we’re reversing the order so we create a countdown. This is done easily inline and can also be used in other loops. Another example is sorting the collection like this.
for index in (0...3).reversed() {
    print("\(index)..")
}

/// 3..
/// 2..
/// 1..
/// 0..
The above examples can be used in a for each loop as well. In fact, forEach calls the given closure on each element in the sequence in the same order as a for-in loop.
let cities = ["Amsterdam", "New York", "San Francisco"]
cities.forEach { city in
    print(city)
}

// Amsterdam
// New York
// San Francisco

let ages = ["Antoine": 28, "Jaap": 2, "Jack": 72]
ages.forEach { name, age in
    print("\(name) is \(age) years old")
}

// Antoine is 28 years old
// Jaap is 2 years old
// Jack is 72 years old

(0...3).reversed().forEach { index in
    print("\(index)..")
}

// 3..
// 2..
// 1..
// 0..
The following example collects the first 10 even numbers of a collection of numbers. For this, we’re using the break and continue statements. The break statement stops the loop, while the continue statements are used to skip the current number.
var evenNumbers = [Int]()
for number in (0...100) {
    guard evenNumbers.count < 10 else {
        break
    }

    guard number % 2 == 0 else {
        continue
    }
    evenNumbers.append(number)
}
print(evenNumbers)

// [0, 2, 4, 6, 8, 10, 12, 14, 16, 18]
We can’t use the break and continue statements using forEach. Therefore, we’re using a filter to get all the even numbers combined with a prefix to get the first 10 items.
let evenNumbers = (0...100).filter { number -> Bool in
    return number % 2 == 0
}.prefix(10)

print(evenNumbers)

// [0, 2, 4, 6, 8, 10, 12, 14, 16, 18]
While loops are less often used but can be really useful. It’s basically executing its statements while the condition is true. The following example is rolling dice until the max amount of tries is reached.
func rollDice() -> Int {
    return (1...6).randomElement()!
}

let maxTries = 6
var tries = 0
var score = 0

while tries < maxTries {
    score += rollDice()
    tries += 1
}

print("Total score is \(score)") // Everytime a random new score!

Source: link

Recent Questions on ios

    Programming Languages