0

This is my code:

struct Book{
    let title: String
    let author: String
    let price: String?
    let pubDate: String?

init?(title: String, author: String, price: String, pubDate: String){
    guard let title = title, let author = author else { // error here
        return nil
    }

    self.title = title
    self.author = author
    self.price = price
    self.pubDate = pubDate
}

}

My error says Initializer for conditional binding must have Option type not 'String' My question is, why do I get this error, if I understand the guard statement correctly, I should only pass in the non-Optional properties before the else, and after the braces, the optional ones, like I've done here.

Jake
  • 53
  • 1
  • 3
  • 8
  • 1
    Your `init?` method does not take any optional arguments. – Perhaps you meant `init?(title: String?, author: String?, ...)` ? – Martin R Jul 10 '16 at 12:27
  • only price and pubDate are optionals in my struct though. Adding `price: String?, pubDate: String?) {...`didn't fix my error however. – Jake Jul 10 '16 at 12:31
  • I'm confused – under what circumstances should your initialiser fail? You cannot use `if let` or `guard let` with non-optionals. – Hamish Jul 10 '16 at 12:38
  • 1
    @JakobHansen: the `title` and `author` parameter of `init?` are **not** optionals, therefore `guard let title = title` does not compile. What did you expect it to do? – Martin R Jul 10 '16 at 12:40
  • If I don't initialize price or pubDate on one instance, I would still like for it to run – Jake Jul 10 '16 at 12:42
  • @MartinR I expected the price: String? and pubDate: String? to be optional, so that on some instances, those properties may be nil. – Jake Jul 10 '16 at 12:49
  • And what is the guard statement for? When do you want your init method to *fail?* – Martin R Jul 10 '16 at 12:51
  • I assumed that I had to use a guard statement to unwrap the 2 optionals ( price and pubDate) I would like my init method to fail, if one of those two optionals are empty / nil. I'd like to be able to create an instance of book like this: let someBook = Book(title: "Harry potter","author: George Lucas","pubDate":"1996") – Jake Jul 10 '16 at 12:59
  • 1
    You are contradicting yourself: Above you said *"If I don't initialize price or pubDate on one instance, I would still like for it to run"* and now you say *"I would like my init method to fail, if one of those two optionals are empty / nil."* – Perhaps I am misunderstanding you. Please add examples **to your question** of init calls that should fail, and examples of init calls that should succeed. – Martin R Jul 10 '16 at 13:10

3 Answers3

0

you can use guard for only optional variables to unwrap expected data or early fail to return from function or loops.Also you don't need to make all parameters optional.There is also other reasons can cause initialization fail.

Ali Kıran
  • 1,006
  • 7
  • 12
0

I would suggest you forego the failable init altogether. Your structure holds a title and author which are not Optional, so make your initializer reflect that. Don't let them try to create a book unless they can provide a title and and author.

The other two properties are Optional. I suggest you provide default values of nil in the initializer for those, which gives your user the most flexibility in creating a Book:

struct Book {
    let title: String
    let author: String
    let price: String?
    let pubDate: String?

    init(title: String, author: String, price: String? = nil, pubDate: String? = nil) {
        self.title = title
        self.author = author
        self.price = price
        self.pubDate = pubDate
    }
}

let book1 = Book(title: "The Hitchhiker's Guide to the Galaxy", author: "Douglas Adams")
let book2 = Book(title: "The Shining", author: "Stephen King", price: "20.00")
let book3 = Book(title: "Little Women", author: "Louisa May Alcott", price: "15.99", pubDate: "1868")
let book4 = Book(title: "Harry Potter", author: "J. K. Rowling", pubDate: "1997")

If you really want to be able to pass in nil for anything, but fail if they don't provide a title and an author, then use guard to unwrap title and author, otherwise fail and return nil:

init?(title: String? = nil, author: String? = nil, price: String? = nil, pubDate: String? = nil) {
    guard let title = title, author = author else { return nil }
    self.title = title
    self.author = author
    self.price = price
    self.pubDate = pubDate
}

// These all return nil
let book5 = Book()
let book6 = Book(title: "War and Peace")
let book7 = Book(author: "Ray Bradbury")
let book8 = Book(title: "Pride and Prejudice", price: "40.00", pubDate: "1813")
vacawama
  • 150,663
  • 30
  • 266
  • 294
-1
struct Book {
    let title: String
    let author: String
    let price: String?
    let pubDate: String?

    init?(dict: [String : String]){
        guard let title = dict["title"], let author = dict["author"] else {
            return nil
        }
        let price = dict["price"]
        let pubDate = dict["pubDate"]

        self.title = title
        self.author = author
        self.price = price
        self.pubDate = pubDate
    }
}
pacification
  • 5,838
  • 4
  • 29
  • 51