0

I am new to Swift and this is the code that gives me an error and somehow it gets past "lastName != nil" even though it has no text.

Thread 1: Fatal error: Unexpectedly found nil while unwrapping an Optional value

func imageFromInitials(firstName: String?, lastName: String?, withBlock: @escaping (_ image: UIImage) -> Void) {

var string: String!
var size = 36

if firstName != nil && lastName != nil {
    string = String(firstName!.first!).uppercased() + String(lastName!.first!).uppercased()
} else {
    string = String(firstName!.first!).uppercased()
    size = 72
}

I am confused and not sure why validation did not work

Andrew
  • 7,619
  • 13
  • 63
  • 117

3 Answers3

3

A string being empty is not the same as it being nil. You need to also check if the strings are empty, or just safely unwrap the first character of the first and last names:

func imageFromInitials(firstName: String?,
                       lastName: String?,
                       withBlock block: @escaping (_ image: UIImage) -> Void) {
    let string: String
    let size: Int

    if let firstInitial = firstName?.first {
        if let lastInitial = lastName?.first {
            string = (String(firstInitial) + String(lastInitial)).uppercased()
            size = 36
        } else {
            string = String(firstInitial).uppercased()
            size = 72
        }
    } else {
        string = ""
        size = 36
    }

    // the rest of your function
}

Or, if you'd like to do it a more "Swifty™" way (and if you're okay with producing a non-empty string for the case where only the lastName is provided), then you could do this:

func imageFromInitials(firstName: String?,
                       lastName: String?,
                       withBlock block: @escaping (_ image: UIImage) -> 
    let string = [firstName, lastName]
        .compactMap { $0?.first }
        .map { String($0) }
        .joined()
        .uppercased()

    let size = string.count == 1 ? 72 : 36

    // the rest of your function
}
TylerP
  • 9,600
  • 4
  • 39
  • 43
2

As the error says:

Unexpectedly found nil while unwrapping an Optional value

What that means is that firstName != nil && lastName != nil is not true. The error you are getting is here:

string = String(firstName!.first!).uppercased()

probably firstName is nil as well.

You can check strings like this firstName .isEmpty. It checks for nil and "" (empty string).

1

You could also use a switch statement like this, so you have more control over what is going on:

func imageFromInitials(firstName: String?, lastName: String?, withBlock: @escaping (_ image: UIImage) -> Void) {

var string = ""
var size = 36

    switch (firstName?.first, lastName?.first) {

    case (.some(let first), .some(let last)):
        string = first.uppercased() + last.uppercased()
    case (.some(let first), nil):
        string = first.uppercased()
        size = 72
    case (nil, .some(let last)):
        string = last.uppercased()
        size = 72
    default:
        print("Both are nil, something is wrong")

    }
    print(string)
    // your code
}

And this post is a little bit old, but it explains why can you use the .some case on optionals, as they are enums.

Swift: testing against optional value in switch case

NicolasElPapu
  • 1,612
  • 2
  • 11
  • 26