Search code examples
swiftsmswatchkitnsurloption-type

WatchKit SMS with preset body


I found this question which should have helped me, but the solution there is not working for me, and I am not sure if something has changed or if the problem is with my code.

let messageBody = "hello"
let urlSafeBody = messageBody.stringByAddingPercentEncodingWithAllowedCharacters(NSCharacterSet.URLHostAllowedCharacterSet())
print("URLSAFEBODY: \(urlSafeBody)")
WKExtension.sharedExtension().openSystemURL(NSURL(string: "sms:&body=\(urlSafeBody)")!)

When this code is executed, I get the message that optional urlSafeBody was force unwrapped while nil, leading to a crash. Why is urlSafeBody nil? I know that I'm force unwrapping it, but I don't understand why it is ever nil after being assigned explicitly.


Solution

  • It's not urlSafeBody that is nil. As you can see from your print statement, it contains an optional string:

    URLSAFEBODY: Optional("hello")

    That will actually turn out to be a problem for the chain in the next statement, since you haven't unwrapped that string before it is interpolated.

    If you examined your NSURL string URL, you'd see it contained:

    sms:&body=Optional("hello")

    This is going to cause NSURL initialization to fail, because its string URL is malformed. The fatal error then happens because you force-unwrapped the nil result from NSURL(string:)

    How to resolve this:

    You want to conditionally unwrap any strings which might be nil. You can do this via if let or guard let optional binding:

    let messageBody = "hello"
    let urlSafeBody = messageBody.stringByAddingPercentEncodingWithAllowedCharacters(NSCharacterSet.URLHostAllowedCharacterSet())
    if let urlSafeBody = urlSafeBody, url = NSURL(string: "sms:&body=\(urlSafeBody)") {
        WKExtension.sharedExtension().openSystemURL(url)
    }
    

    Notice that the urlSafeBody was unwrapped before it was used in the string interpolation, and url was also unwrapped after initialization.

    Since it's certain that the url is not nil, it can be safely passed to openSystemURL.

    You should always strive to avoid force-unwrapping variables which may be nil, as that will certainly lead to a crash.