JibW
JibW

Reputation: 4562

SWIFT: NSURLSession convert data to String

In my iPhone application (develops in SWIFT) I've got to communicate with a https service (with parameters) and needs to analyse the response.

All works ok but in some cases noticed it does NOT getting the expected result... Further analysing I found it's the problem about converting server respone data to string (NSData -> NSString)...

1). When I use UTF8 Encoding I am getting nil as converted String (responseString )

    let responseString = NSString(data: data, encoding: NSUTF8StringEncoding)

2). But with ASCII encoding it's fine (Gets the correct response server provides)

    let responseString = NSString(data: data, encoding: NSASCIIStringEncoding)

Following is a full sample code I am trying...

    let myUrl = NSURL(string: "https://myurl.com/myservice.asp")
    let request = NSMutableURLRequest(URL: myUrl!)

    request.HTTPMethod = "POST"
    request.timeoutInterval = 55.0
    let postString = "paramone=\(para1)&paramtwo=\(para2)&paramthree=\(para3)"

    // NOTE: Works ok with ASCII AND UTF8 both encoding types at this point...
    // request.HTTPBody = postString.dataUsingEncoding(NSASCIIStringEncoding)
    request.HTTPBody = postString.dataUsingEncoding(NSUTF8StringEncoding)

    let task = NSURLSession.sharedSession().dataTaskWithRequest(request) { data, response, error in

        if (error != nil)
        {
            println("Error: \(error)")
            println("Description: \(error.description)")
            println("Domain     : \(error.domain)")
            println("Error code : \(error.code)")
        }
        else
        {
            //???? => ENCODING PROBLEM
            // let responseString = NSString(data: data, encoding: NSASCIIStringEncoding)
            let responseString = NSString(data: data, encoding: NSUTF8StringEncoding)

            println("Response: \(responseString)")
        }
    }
    task.resume()

I came across with few other POSTS explaining the same issue... But NOT sure if it's good to go with ASCII rather than UTF8...

Also I can't understand the response contains '£' sign and works ok with ASCII encoding (eventhough '£' is NOT in ASCII character Set), BUT NOT with UTF8.

Like to hear if I am missing anything or what the best way to go with this... Thanks.

Upvotes: 5

Views: 10737

Answers (2)

Princess
Princess

Reputation: 319

@JibW this code will helps you to analyse response and easy to understand...do some additional changes as per your requirements.!

    let URL = NSURL(string: "Paste your url here")!
    var request = NSMutableURLRequest(URL: URL)
    var session = NSURLSession.sharedSession()
    request.HTTPMethod = "POST"
    request.timeInterval = 55.0
    var error: NSError?
    request.HTTPBody = NSJSONSerialization.dataWithJSONObject(parameters, options: nil, error: &error)
    request.addValue("application/json", forHTTPHeaderField: "Content-Type")
    request.addValue("application/json", forHTTPHeaderField: "Accept")


    var data: NSData!
    var response: NSURLResponse!

    var task = session.dataTaskWithRequest(request, completionHandler: {data, response, error -> Void in

        var httpResponse = response as! NSHTTPURLResponse
        println("\(httpResponse.statusCode)")

        var strData = NSString(data: data, encoding: NSUTF8StringEncoding)
        println("Body: \(strData)")

         var err: NSError?
        var json = NSJSONSerialization.JSONObjectWithData(data, options: .MutableLeaves, error: &err) as? NSDictionary

         if(err != nil) {
            println(err!.localizedDescription)
            let jsonStr = NSString(data: data, encoding: NSUTF8StringEncoding)
            println("Error could not parse JSON: '\(jsonStr)'")
        }

        else

        {
            // The JSONObjectWithData constructor didn't return an error. But, we should still
            // check and make sure that json has a value using optional binding.
            if let parseJSON = json {
                // Okay, the parsedJSON is here, let's get the value for 'success' out of it
                var success = parseJSON["success"] as? Int
                println("Succes: \(success)")
            }

            else {

                // Woa, okay the json object was nil, something went worng. Maybe the server isn't running?
                let jsonStr = NSString(data: data, encoding: NSUTF8StringEncoding)
                println("Error could not parse JSON: \(jsonStr)")
            }
        }
    })

    task.resume()

Upvotes: 6

Martin R
Martin R

Reputation: 539705

NSASCIIStringEncoding is documented as a strict 7-bit encoding for the ASCII values 0 .. 127. However, experiments show that when decoding NSData to (NS)String, it accepts arbitrary data and interprets the bytes 0 .. 255 as the Unicode characters U+0000 .. U+00FF. So when decoding, NSASCIIStringEncoding behaves identically to NSISOLatin1StringEncoding:

let bytes = (0 ..< 256).map { UInt8($0) }
let data = NSData(bytes: bytes, length: bytes.count)

let s1 = String(data: data, encoding: NSASCIIStringEncoding)!
let s2 = String(data: data, encoding: NSISOLatin1StringEncoding)!
print(s1 == s2) // true

This can explain why a character like "£" is decoded correctly even if it is not in the ASCII character set.

But note that this behavior is (as far as I know) not documented, so you should not rely on it. Also this does not work when encoding (NS)String to NSData:

let d1 = s1.dataUsingEncoding(NSASCIIStringEncoding) // nil

If the server sends a HTTP response header with a Content-Type = charset=... field then you can detect the encoding automatically, see https://stackoverflow.com/a/32051684/1187415.

If the server does not send the response encoding in the HTTP response header then you can only try different encodings. Frequently used encodings are

  • NSUTF8StringEncoding for the UTF-8 encoding,
  • NSWindowsCP1252StringEncoding for the Windows-1252 encoding,
  • NSISOLatin1StringEncoding for the ISO-8859-1 encoding.

There is also a NSString method which can detect the used encoding, however this requires that you write the data to a file first, see Convert TXT File of Unknown Encoding to String.

Upvotes: 7

Related Questions