WWDC24 SALE: Save 50% on all my Swift books and bundles! >>

Day 8 Throwing Functions, Generalizing the function

Forums > 100 Days of SwiftUI

I have a question regarding gereralizing throwing functions, specifically with regard to addind the do/catch to it's own function. The examples in 100 Days of SwiftUI as well as other documentation I found online shows that to use throwing functions, we should create an enum, a function, and then use do/catch to try the code. My question is where should the do catch go? What is the best way to generalize it? In the Day 8 example that I used to guide my code for Checkpoint 4 - Integer square, it seems that I should hardcode the square.

See the example in the the section labeled "START ORIGINAL EXAMPLE" where I created a function, "integerSquare"

I then decided to to rename "integerSquare" to integerSquareRunner, that gets called by "integerSquare." That way, "integerSquare" could be called with different inputs, such as: integerSquare(of: 15) That code can be found in the section labeled "START UPDATED EXAMPLE"

It works as I intended, but is this good practice? Is there another way that this same functionality can be accomplished?

Thank you in advance...

import UIKit

enum SquareRootError: Error {
    case outOfBounds, noRoot
}

// **** START ORIGINAL EXAMPLE /*

func integerSquare(of num: Int) throws -> Int {
     if num < 1 || num > 10000 { throw SquareRootError.outOfBounds}
     for i in 1...10000 {
         if i * i == num {
             return i
         }
     }

     throw SquareRootError.noRoot
 }

 do {
     var square = try integerSquare(of: 10000)
     print(square)
 }
 catch SquareRootError.outOfBounds {
     print("The number that you entered is out of bounds.")
 }
 catch SquareRootError.noRoot {
     print("There is no perfect root for number that you entered.")
 }

*/
//**** END ORIGINAL EXAMPLE

// **** START UPDATED EXAMPLE

func integerSquareRunner(of num: Int) throws -> Int {
    if num < 1 || num > 10000 { throw SquareRootError.outOfBounds}
    for i in 1...10000 {
        if i * i == num {
            return i
        }
    }

    throw SquareRootError.noRoot
}

func integerSquare(of num: Int){
    do {
        var square = try integerSquareRunner(of: num)
        print(square)
    }
    catch SquareRootError.outOfBounds {
        print("The number that you entered is out of bounds.")
    }
    catch SquareRootError.noRoot {
        print("There is no perfect root for number that you entered.")
    }
    catch {
        print("There was an error: \(error.localizedDescription)")
    }
}

integerSquare(of: 15)

//**** END UPDATED EXAMPLE

   

Please edit your post and put ALL YOUR CODE inside the code markup tags. Thanks.

   

You should put the do ... catch wherever you plan to handle the error.

Creating a whole new function just to have somewhere to catch errors is overcomplicating things. Your first example is the way to go.

1      

You can reduce the amount of zeros here to 100.....

for i in 1...10000 {

You are returning i x i from range 1 to 10000. 100 x 100 is 10000. 100 x 101 is higher than 10000, so there's not much point in that.

As far as do and catch goes try not to write code that will crash :)!

   

I would change a few thing (not sure that you have covered this in the 100Days) but use a guard instead of if in the method. At the moment you are learning about them and can not see how they would work so did this as an example. You have a model class that you would put the throwing method in

@Observable
class SomeModel {
    var inputNumber = 0

    func squareRoot(of num: Int) throws -> Int {
         guard num > 1 && num < 10000 else { throw SquareRootError.outOfBounds }

         for i in 1...100 {
             if i * i == num {
                 return i
             }
         }

         throw SquareRootError.noRoot
     }
}

Then in the View it can be used

struct ContentView: View {
    @State private var model = SomeModel()

    var displaySquareRoot: String {
        do {
            let root = try model.squareRoot(of: model.inputNumber)
            return "Answer: \(root)"
        } catch SquareRootError.outOfBounds {
            return "The number that you entered is out of bounds."
        } catch SquareRootError.noRoot {
            return "There is no perfect root for number that you entered."
        } catch {
            return "There was an error: \(error.localizedDescription)"
        }
    }

    var body: some View {
        VStack {
            LabeledContent("Enter Number: ") {
                TextField("Enter Number", value: $model.inputNumber, format: .number)
                    .textFieldStyle(.roundedBorder)
                    .multilineTextAlignment(.center)
            }

            Text(displaySquareRoot)
                .padding()

        }
        .padding()
    }
}

As you can see that handling errors at the call site to display to user.

   

Save 50% in my WWDC sale.

SAVE 50% To celebrate WWDC24, all our books and bundles are half price, so you can take your Swift knowledge further without spending big! Get the Swift Power Pack to build your iOS career faster, get the Swift Platform Pack to builds apps for macOS, watchOS, and beyond, or get the Swift Plus Pack to learn advanced design patterns, testing skills, and more.

Save 50% on all our books and bundles!

Reply to this topic…

You need to create an account or log in to reply.

All interactions here are governed by our code of conduct.

 
Unknown user

You are not logged in

Log in or create account
 

Link copied to your pasteboard.