1

I am trying to learn swift ViewModel and I have created a function to handel the error.

But when I call the function in my ViewController file it says :

Cannot assign to value: 'error' is a 'let' constant

Is there any way to fix this? I am still a student looking for the best advice.

Thanks a lot.

Below is my code can you guys please help me.

SignUpError.swift :

class SingUpError {
    func errorMessage(name: String?, lastName: String?,email: String?, password: String?, error: String?){

        enum ErrorMessage: String {
            case noName = "Name cannot be empty"
            case noLastName = "Last name cannot be empty"
            case noEmail = "Email cannot be empty"
            case noPassword = "Password cannot be empty"
        }

        if name == "" {
            error = ErrorMessage.noName.rawValue
        }
    }
}

NewUserVC.swift :

class NewUserVC: UIViewController {

    // Var
    var vm = SingUpError()

    // Outlet Text Fields

    @IBOutlet weak var nameText: UITextField!
    @IBOutlet weak var lastNameText: UITextField!
    @IBOutlet weak var emailText: UITextField!
    @IBOutlet weak var passwordText: UITextField!

    // Outlet Labels

    @IBOutlet weak var nameErrLbl: UILabel!
    @IBOutlet weak var lastNameErrLbl: UILabel!
    @IBOutlet weak var emailErrLbl: UILabel!
    @IBOutlet weak var passwordErrLbl: UILabel!


    @IBAction func submiButton(_ sender: UIButton) {
        submitData()
    }

    override func viewDidLoad() {
        super.viewDidLoad()
    }

    func submitData() {
        guard
            let name = nameText.text,
            let lastName = lastNameText.text,
            let email = emailText.text,
            let password = passwordText.text
            else {return}

        vm.errorMessage(name: name, lastName: lastName, email: email, password: password, error: nameErrLbl.text)
    }
}
Sharad Chauhan
  • 4,821
  • 2
  • 25
  • 50

8 Answers8

0

You need to do something like this

class SingUpError {
    func errorMessage(name: String?, lastName: String?,email: String?, password: String?, error: String?) -> String{

        var errorMessage : String = ""

        enum ErrorMessage: String {
            case noName = "Name cannot be empty"
            case noLastName = "Last name cannot be empty"
            case noEmail = "Email cannot be empty"
            case noPassword = "Password cannot be empty"
        }

        if name == "" {
            errorMessage = ErrorMessage.noName.rawValue
        }

        return errorMessage
    }
}  
Hardik Thakkar
  • 15,269
  • 2
  • 94
  • 81
0

When you declare a function on swift, its parameters are by default 'let' constants. And we can not assign value to constants.

In your case, you are trying to assign to 'error' variable, which is a parameter, hence a constant(let). You can not do that.

You could return an error message

class SingUpError {
    func errorMessage(name: String?, lastName: String?,email: String?, password: String?) -> String{

        enum ErrorMessage: String {
            case noName = "Name cannot be empty"
            case noLastName = "Last name cannot be empty"
            case noEmail = "Email cannot be empty"
            case noPassword = "Password cannot be empty"
        }

        if name == "" {
            return ErrorMessage.noName.rawValue
        }

        return ""
    }
}
Hardik Thakkar
  • 15,269
  • 2
  • 94
  • 81
varsim
  • 70
  • 9
0

I'm not entirely sure what you're trying to do with SingUpError (do you mean SignUpError?) but this is my attempt at it. Basically I am moving the enum out of the func and I make the func return a String

class SingUpError  {
    enum ErrorMessage: String {
        case noName = "Name cannot be empty"
        case noLastName = "Last name cannot be empty"
        case noEmail = "Email cannot be empty"
        case noPassword = "Password cannot be empty"
    }

    func errorMessage(name: String?, lastName: String?,email: String?, password: String?) -> String? {
        var message: String?

        if name == nil || name.isEmpty {
            message = ErrorMessage.noName.rawValue
        } //else if lastName...

        return message
    }
}

and then in submitData

if let error = vm.errorMessage(name: name, lastName: lastName, email: email, password: password) {
     nameErrLbl.text = error
}
Joakim Danielson
  • 43,251
  • 5
  • 22
  • 52
0

You trying to assign value to constant.

You can't do that, because error it's parameter of function. If you want to get error message from this function you need to write something like:

return ErrorMessage.noName.rawValue

instead

error = ErrorMessage.noName.rawValue
Bogdan Evsenev
  • 851
  • 9
  • 16
0
class SingUpError {
    func errorMessage(name: String?, lastName: String?,email: String?, password: String?) -> String? {

        guard let _ = name else { return ErrorMessage.noName.rawValue }

        // <this seems incomplete, but..>
        enum ErrorMessage: String { 
            case noName = "Name cannot be empty"
            case noLastName = "Last name cannot be empty"
            case noEmail = "Email cannot be empty"
            case noPassword = "Password cannot be empty"
        }

        return nil
    }
}
Chris Conover
  • 8,889
  • 5
  • 52
  • 68
0

Firstly, put this enum out of the class SignUpError

enum ErrorMessage: String {
        case noName = "Name cannot be empty"
        case noLastName = "Last name cannot be empty"
        case noEmail = "Email cannot be empty"
        case noPassword = "Password cannot be empty"
    }

secondly, you can modify your function like this:

func errorMessage(name: String?, lastName: String?,email: String?, password: String?) -> String? {
    if name == "" {
        let error = ErrorMessage.noName.rawValue
        return error
    }
    return nil
}

Now in your ViewController, you can modify your function to get the errorMessage like this

func submitData() {
    //YOUR EXISTING CODE HERE    
    if let errorMessage = vm.errorMessage(name: name, lastName: lastName, email: email, password: password) {
        print("errorMessage:\(errorMessage)")
        return
    }
}

OR You can try the same approach you are having but by passing error as inout parameter. similar question here

Bhavin Kansagara
  • 2,866
  • 1
  • 16
  • 20
0

As other answers have said you can't assign to the 'error' parameter because it is a constant (a let variable if you will). Now you can go down the route of modifyig the function to return as string as suggested but you would be better off adopting a more structured approach and actually throwing an error.

Something like this would do:

enum sumbissionErrors: Error {
    case noName
    case noLastName
    case noEmail
    case noPassword

    var description: String {
        switch self {
        case .noName:
            return "Name cannot be empty"
        case .noLastName:
            return "Last name cannot be empty"
        case .noEmail:
            return "Email cannot be empty"
        case .noPassword:
            return "Password cannot be empty"
        }
    }
}

func submitData() throws {
    if nameText.text == nil || nameText.text!.isEmpty {
        throw sumbissionErrors.noName
    }

    if lastNameText.text == nil || lastNameText.text!.isEmpty {
        throw sumbissionErrors.noLastName
    }

    if emailText.text == nil || emailText.text!.isEmpty {
        throw sumbissionErrors.noEmail
    }

    if passwordText.text == nil || passwordText.text!.isEmpty {
        throw sumbissionErrors.noPassword
    }

    // Do whatever you want now that the data is valid.
}

@IBAction func submitButton(_ sender: UIButton) {
    do {
        try submitData()
    }
    catch {
        if let sumbmissionError = error as? sumbissionErrors {
            switch sumbmissionError {
            case .noName:
                nameErrLbl.text = sumbmissionError.description
            case .noLastName:
                lastNameErrLbl.text = sumbmissionError.description
            case .noEmail:
                emailErrLbl.text = sumbmissionError.description
            case .noPassword:
                passwordErrLbl.text = sumbmissionError.description
            }
        } else {
            // This will probably never happen but it indicates that some other more general error occured and needs to be handled here.
        }
    }
}

This is just an example and like your original will only throw the first error it comes across. You might want to re-structure everything to allow multiple errors to be flagged. I.e. it's possible that more than one of them could be empty.

Upholder Of Truth
  • 4,643
  • 2
  • 13
  • 23
0

If you want to go with same approach you used then you need to change some minor thing in your function.

First thing function parameter is let constant means you cannot assign the value but if you still need to assign some value to your parameter then there will be one way used inout keyword in function

class SingUpError {
    func errorMessage(name: String?, lastName: String?,email: String?, password: String?, error: inout String?){

        enum ErrorMessage: String {
            case noName = "Name cannot be empty"
            case noLastName = "Last name cannot be empty"
            case noEmail = "Email cannot be empty"
            case noPassword = "Password cannot be empty"
        }

        if name == "" {
            error = ErrorMessage.noName.rawValue
        }
    }
}

calling

vm.errorMessage(name: name, lastName: lastName, email: email, password: password, error: &nameErrLbl.text)

Here is some reference link too

When to use inout parameters?

Chirag Shah
  • 3,034
  • 1
  • 30
  • 61