5

I am working on a Swift 3.0 app, in which I am making a rest api call. The problem is that there may be a space in query string parameter, which is causing the URL to become nil. It works fine when there is no space in that parameter. But with a space it does not work.

Any help is appreciated.

Thanks

Sundeep Saluja
  • 1,089
  • 2
  • 14
  • 36

3 Answers3

11

You could do something like this to escape the spaces and other characters which may interfere with the request processing:

var escapedAddress = address.stringByAddingPercentEncodingWithAllowedCharacters(NSCharacterSet.URLQueryAllowedCharacterSet())

For Swift 3, use the following:

let escapedAddress = address.addingPercentEncoding(withAllowedCharacters: CharacterSet.urlQueryAllowed)
userx
  • 1,083
  • 5
  • 18
  • 36
1

You need to percent-escape the httpBody data:

Manually build the body

let parameters = [
    "customer": "John Smith",
    "address": "123 Fake St., Some City"
]

let httpBody = parameters.map {
    $0 + "=" + $1.addingPercentEncoding(withAllowedCharacters: .urlQueryAllowed)!
}
    .joined(separator: "&")
    .data(using: .utf8)!

While the parameter's name can contain special characters, this is extremely rare. If your API happens to use that, escape $0 in the closure as well.

Using URLComponents

var components = URLComponents()
components.queryItems = [
    URLQueryItem(name:"customer", value: "John Smith"),
    URLQueryItem(name:"address", value: "123 Fake St., Some City")
]

// Drop the `&` character in front of the query string
let httpBody = components.string!.dropFirst().data(using: .utf8)!

URLComponents will automatically encode any special character in both the parameter's name and value. This also guarantee the order of the parameters in the POST data, which is important for some API calls.

Code Different
  • 90,614
  • 16
  • 144
  • 163
0

Ideally you'd be able to use URLQueryItem as in the answer above but I've never seen it replace spaces correctly. You can try this code in a newly created project to see what happens (Swift 4):

func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
    // first example
    var components = URLComponents(string: "http://www.whatever.com/foo")!

    components.queryItems = [URLQueryItem(name: "feh", value: "feh"), URLQueryItem(name: "blah", value: "blah blah")]
    NSLog("\(components.url!)")

    // second example
    components = URLComponents(string: "http://www.whatever.com/foo")!

    components.queryItems = [URLQueryItem(name: "feh", value: "feh"), URLQueryItem(name: "blah", value: "blah blah"), URLQueryItem(name: "var with spaces", value: "here is a longer string with spaces in it")]
    NSLog("url=\(components.url!)")
    NSLog("string=\(components.string!)")
    NSLog("\(components.queryItems!)")
    NSLog("\(components.query!)")

    return true
}

This returns

2017-09-25 22:57:13.277885-0500 Bug29554407[10899:7054940] http://www.whatever.com/foo?feh=feh&blah=blah2lah

2017-09-25 22:57:13.278234-0500 Bug29554407[10899:7054940] url=http://www.whatever.com/foo?feh=feh&blah=blah2lah&var2ith(null)paces=here 0s 0x0p+0 0nger(null)tring2ith(null)paces 0n 0t

2017-09-25 22:57:13.278359-0500 Bug29554407[10899:7054940] string=http://www.whatever.com/foo?feh=feh&blah=blah2lah&var2ith(null)paces=here 0s 0x0p+0 0nger(null)tring2ith(null)paces 0n 309458872t

2017-09-25 22:57:13.280232-0500 Bug29554407[10899:7054940] [feh=feh, blah=blah blah, var with spaces=here is a longer string with spaces in it]

2017-09-25 22:57:13.280334-0500 Bug29554407[10899:7054940] feh=feh&blah=blah blah&var with spaces=here is a longer string with spaces in it

I wonder if there is some sort of Swift/Objc difference between strings because the problem doesn't happen when using Objective-C.

Michael Link
  • 301
  • 2
  • 3