Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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.

like image 652
JibW Avatar asked Sep 21 '15 11:09

JibW


People also ask

How do you convert something to a string in Swift?

To convert an Int value to a String value in Swift, use String(). String() accepts integer as argument and returns a String value created using the given integer value.

What is NSURLSession in Swift?

Overview. The NSURLSession class and related classes provide an API for downloading data from and uploading data to endpoints indicated by URLs. Your app can also use this API to perform background downloads when your app isn't running or, in iOS, while your app is suspended.

What is data in Swift?

Data in Swift 3 is a struct that conforms to collection protocol. It is a collection of bytes ( [UInt8] array of unsigned integer 8 bits 0-255). – Leo Dabus.


Video Answer


2 Answers

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.

like image 117
Martin R Avatar answered Oct 23 '22 10:10

Martin R


@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()
like image 42
Princess Avatar answered Oct 23 '22 10:10

Princess