0

I’m new to Swift and writing an app that reads data from a scanner then posts it to a web page. I am taking the data from a text edit field on my main storyboard for now and when I press a lookup button to trigger the following code it throws the below exception. I set a break point and checked the value of temp prior to its use in the URL and its colored in correctly (not nil). If I type into the edit field then the code works fine from then on; opens the page even if I delete the contents of the edit field using the clear icon (x).

I’m at a loss to understand which variable is nil and how to correct or protect the code. Any help would be appreciated.

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

func setStatus(_ status: String)
{
    statusLabel.text = status
}

func processRead(_ data: String?)
{
    if (data != nil)
    {
        var temp: String = data!
        setStatus(temp)

        temp = "foo.com?data=" + temp

        let url: URL = URL(string: temp)!      //  <<<< THROWS EXCEPTION / BREAK POINT 
        UIApplication.shared.openURL(url)
    }
}

UPDATE -- Corrected code --

func setStatus(_ status: String)
{
    statusLabel.text = status
}


func processRead(_ data: String?)
{
    if (data != nil && !data!.isEmpty)
    {
        let temp = "https://foo.com/data=" + data!.addingPercentEncoding(withAllowedCharacters: CharacterSet.urlQueryAllowed)!);
        if let url = URL(string: temp)
        {
            setStatus(data!)
            UIApplication.shared.openURL(url)
        }
        else
        {
            print("Bad URL: " + temp);
        }
    }
}
glez
  • 1,170
  • 3
  • 16
  • 42
  • 2
    Possible duplicate of [What does "fatal error: unexpectedly found nil while unwrapping an Optional value" mean?](https://stackoverflow.com/questions/32170456/what-does-fatal-error-unexpectedly-found-nil-while-unwrapping-an-optional-valu) – Carcigenicate May 29 '18 at 15:17
  • I read that post but I don't see what is nil. temp contains a valid URL string – glez May 29 '18 at 15:19
  • 2
    `URL(string: temp)` must be evaluating to `nil`. Check the documentation for that function to see in what cases it returns `nil`. I'm going to guess that means that the address you're giving it isn't a valid URL. – Carcigenicate May 29 '18 at 15:21

2 Answers2

3

There is a possibility that temp contains some characters that are invalid in the query part of a URL. This makes the whole string not a valid URL, so URL.init returns nil. You need to escape those characters by calling addingPercentEncoding:

URL(string: "foo.com?data=" + temp.addingPercentEncoding(withAllowedCharacters: CharacterSet.urlQueryAllowed)!)
Sweeper
  • 213,210
  • 22
  • 193
  • 313
  • While this may be needed, the immediate problem is the lack of a scheme. – rmaddy May 29 '18 at 15:26
  • @rmaddy I tried the code and it successfully creates a `URL`, so schemes are optional, no? – Sweeper May 29 '18 at 15:27
  • While this might be needed, this wont encode query params correctly when it contains ? or & or =. – Sulthan May 29 '18 at 15:28
  • It is odd that this code results in a non-nil URL despite the lack of URL scheme. – rmaddy May 29 '18 at 15:31
  • The above worked perfectly. Perhaps the edit field returns something with unacceptable characters for a URL because it only happens prior to touching into the edit field and a bad URL string throws an exception even though its non-nil, non-blank. Thanks for the quick help. All is well for now. – glez May 29 '18 at 15:37
  • So I could do this to protect the code: let url: URL? = URL(string: temp) if (url != nil) { UIApplication.shared.openURL(URL("foo.com/data=" + temp)!) } } – glez May 29 '18 at 15:59
  • 2
    @zappullae The proper way is `if let url = URL(string: temp) { UIApplication.shared.openURL(url) } else { print("bad url") }`. – rmaddy May 29 '18 at 16:51
0

What happens is that when initizlizing the URL object with the temp string, it can't successfully convert the string into a URL. As URL initializer init?(string: String) is an optional initializer it can return nil if there is an error converting the sting into an URL. Try adding "https://" to you string.

 temp = "https://foo.com?data=" + temp
Enrique Bermúdez
  • 1,740
  • 2
  • 11
  • 25