Search code examples
javaswiftfailable

New to Swift - failable initializers


I am trying to convert a Java class to Swift:

// Card class with only a main function
public class Card {
// fields
private int numvalue;

// constructor(s)
public Card(int v) {
    if (v > 0 && v < 11) {
        this.numvalue = v;}
    else {
        System.out.println("Error: Card value is outside the allowed range.
        Value must be between 1 and 10 inclusive.")
    }

If I try to initialize a Card object using the constructor with a value that isn't between 1 and 10, the initialization fails, and a statement is printed in the Terminal explaining that the value was not within the acceptable range. I tried to recreate this in Swift.

class Card {
    var numValue : Int?
    init(numValue:Int) {
        if (numValue > 0 && numValue < 11) {self.numValue = numValue}
        else {print("Card value must be between 0 and 11")}
    }
    func setNumValue(value:Int) -> () {
        self.numValue = value
    }
    func getNumValue() -> Int {
        return self.numValue!
    }
}

The above works in the proper cases, but it appears to still create a Card instance even when an unacceptable value is passed, because I can still use the setNumValue(value:) method to change the value.

I tried making the init(numvalue:) method failable, but then I get an Optional(Card) if initialization is successful. Ideally, I'd like for any successfully initialized Card object to be a Card object, not an Optional containing a Card. Is this possible?


Solution

  • Well, you'll have to check the returned Optional whether it is nil or not, and then unwrap it into a non-Optional:

    class Card {
        var numValue : Int
        init?(numValue:Int) {
            guard (numValue > 0 && numValue < 11) else {
                print("Card value must be between 0 and 11")
                return nil
            }
    
            self.numValue = numValue
        }
        func setNumValue(value:Int) -> () {
            guard (numValue > 0 && numValue < 11) else {
                print("Card value must be between 0 and 11")
                return
            }
            self.numValue = value
        }
        func getNumValue() -> Int {
            return self.numValue
        }
    }
    
    
    let cOk = Card(numValue:1)
    let cFails = Card(numValue:-1)
    
    if let c = cOk {
        // now work with c because it's a Card,
        // not an Optional<Card> 
    }