-1

I have extension which I declared in separate swift file which I use to handle errors when user fill out registration information. But instead to return String in my debug are I want to use some alerts or imageViews to display depends on the error. The problem is that I'm not sure how can I pass IBOutlet or create alert in return section of this extension. For example if firstName is empty, red circle alert (imageView) will be displayed near the firstName textfield. Maybe my architecture of handling errors is wrong or maybe there is a way how to do it?

I would be very grateful if you give me a right direction where to find solution.

Here is the extension

import UIKit

enum RegistrationErrors: Error {
    case invalidFirstName
    case invalidLastName
    case invalidCountry
}

extension RegistrationErrors: CustomStringConvertible {
var description: String {
    switch self {
    case .invalidFirstName:
        return "FirstName cannot be empty"

    case .invalidLastName:
        return "LastName cannot be empty"

    case .invalidCountry:
        return "Country cannot be empty"
    }
}

}

Here is my code where I use this extension

func registrationUser(firstName: String, lastName: String, country: String) throws -> (String, String, String)   {
    guard let firstName = firstNameTextField.text , firstName.characters.count != 0 else {
        throw RegistrationErrors.invalidFirstName
    }

    guard let lastName = lastNameTextField.text , lastName.characters.count != 0 else {
        throw RegistrationErrors.invalidLastName
    }

    guard let country = countryTextField.text , country.characters.count != 0 else {
        throw RegistrationErrors.invalidCountry
    }

    return (firstName, lastName, country)
}

// MARK: Actions

@IBAction func continueBtnTapped(_ sender: Any) {

    do {
        let (firstName, lastName, country) = try registrationUser(firstName: firstNameTextField.text!, lastName: lastNameTextField.text!, country: countryTextField.text!)
        if let currentUser = FIRAuth.auth()?.currentUser?.uid {
            DataService.instance.REF_BASE.child("users").child("profile").setValue(["firstName": firstName, "lastName": lastName, "country": country, "userId": currentUser])
            performSegue(withIdentifier: "toUsersList", sender: self)
        }
    } catch let error as RegistrationErrors {
        print(error.description)
    } catch {
        print(error)
    }
}
Sargot
  • 73
  • 2
  • 6
  • Related: http://stackoverflow.com/questions/39176196/how-to-provide-a-localized-description-with-an-error-type-in-swift. – Martin R Mar 12 '17 at 19:10
  • @MartinR In fact I was thinking closing this as a duplicate of that one. The only reason I didn't is that I wasn't entirely certain whether this is what the OP was asking. – matt Mar 12 '17 at 20:03

2 Answers2

0

Your RegistrationErrors CustomStringConvertible extension is not a bad idea. I think you'll want to handle showing the error to the user right in that do..catch block.

You can catch specific errors like:

do {
  ... try registerUser(...)
} catch RegistrationErrors.invalidFirstName {
  view.invalidFirstName()
} catch ...

You can also capture the error when it is a RegistrationError, like you are doing, then handle the specific error in a switch:

// ...
catch let error as RegistrationErrors {
  print(error)
  switch error {
    case .invalidFirstName:
        view.invalidFirstName()
    // ...
  }
hola
  • 3,150
  • 13
  • 21
0

Instead of deriving your error from Error, derive it from LocalizedError. This allows you to provide an errorDescription property, and you can even localize it later if you like:

enum RegistrationErrors: LocalizedError {
    case invalidFirstName
    case invalidLastName
    case invalidCountry
    var errorDescription : String? {
        switch self {
        case .invalidFirstName: return NSLocalizedString(
            "First name cannot be empty", comment:"First name cannot be empty")
        case .invalidLastName: return NSLocalizedString(
            "Last name cannot be empty", comment:"Last name cannot be empty")
        case .invalidCountry: return NSLocalizedString(
            "Country cannot be empty", comment:"Country cannot be empty")
        }
    }
}

This becomes the error's localizedDescription at the catch point:

do {
    throw RegistrationErrors.invalidLastName
} catch {
    let problem = error.localizedDescription
    // "Last name cannot be empty"
    // ... now present your alert ...
}

This is a universal solution. No special code is necessary; the catch point does not have to be aware of any extra property of the error, and it even works if the catch point is Objective-C code, because the localized description just carries over into the NSError version.

matt
  • 515,959
  • 87
  • 875
  • 1,141