Why my return is nil but if i press the url in chrome/safari, i can get data?
Asked Answered
M

2

3
@IBAction func mainButtonnBeTapped(sender: AnyObject) {
        let session = NSURLSession.sharedSession()
        let request = NSURLRequest(URL: NSURL(string: "http://hq.sinajs.cn/list=sz000609")!)
        let task = session.dataTaskWithRequest(request, completionHandler: {
            (data, response, error) -> Void in            
            let myString = NSString(data: data, encoding: NSUTF8StringEncoding)
            println("this is my string: \(myString)")
        })
        task.resume()
    }

I am using above url to try to get some data, but the return is nil, but i enter the url in chrome/safari, i can get some data. I really don't why, can anyone help to explain?

Monospermous answered 17/8, 2015 at 12:53 Comment(3)
What exactly is nil?Parsee
@nhgrif, you see, i have a println() function, in the console, the result is: this is my string: nilMonospermous
What's the response parameter? (It is non-nil?)Parsee
L
3

The text you try to get is probably not UTF-8, try with another encoding, like this for example:

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

Update: read Martin R's answer for how to find the right encoding.

Longhair answered 17/8, 2015 at 13:12 Comment(4)
While it might be possible that the result was not UTF-8 encoding... I don't think this would actually result in the string being nil (versus simply unintelligible).Parsee
It seems like it is GBK and according to the list of available encodings it is probably kCFStringEncodingGB_18030_2000Spiegelman
@Parsee I just tested in a Playground, it is nil with NSUTF8StringEncoding but works with NSASCIIStringEncoding. :) Although I'm not sure this ASCII encoding is the right one for OP, it doesn't return nil anymore with it.Longhair
@nhgrif: NSString(data:encoding:) does return nil if the data is not valid in the specified encoding, and data in GBK encoding is unlikely to be valid UTF-8.Ever
E
12

This HTTP server sends a

Content-Type = application/x-javascript; charset=GBK

header field in the response, therefore you get the correct encoding from the textEncodingName property of the NSURLResponse. This can be converted to a NSStringEncoding.

This is just a translation of the solution presented in https://mcmap.net/q/1330688/-function-to-detect-the-nsstringencoding-from-nsurlresponse to Swift, plus some simple error checking:

let session = NSURLSession.sharedSession()
let request = NSURLRequest(URL: NSURL(string: "http://hq.sinajs.cn/list=sz000609")!)
let task = session.dataTaskWithRequest(request, completionHandler: {
    (data, response, error) -> Void in   

    var usedEncoding = NSUTF8StringEncoding // Some fallback value
    if let encodingName = response.textEncodingName {
        let encoding = CFStringConvertEncodingToNSStringEncoding(CFStringConvertIANACharSetNameToEncoding(encodingName))
        if encoding != UInt(kCFStringEncodingInvalidId) {
            usedEncoding = encoding
        }
    }
    if let myString = NSString(data: data, encoding: usedEncoding) {
        println("this is my string: \(myString)")
    } else {
        println("failed to decode data")
    }
})
task.resume()

Output:

this is my string: var hq_str_sz000609="绵世股份, ....

Minor changes are necessary for Swift 2:

let session = NSURLSession.sharedSession()
let request = NSURLRequest(URL: NSURL(string: "http://hq.sinajs.cn/list=sz000609")!)
let task = session.dataTaskWithRequest(request, completionHandler: {
    (data, response, error) -> Void in   

    var usedEncoding = NSUTF8StringEncoding // Some fallback value
    if let encodingName = response?.textEncodingName {
        let encoding = CFStringConvertEncodingToNSStringEncoding(CFStringConvertIANACharSetNameToEncoding(encodingName))
        if encoding != UInt(kCFStringEncodingInvalidId) {
            usedEncoding = encoding
        }
    }
    if let myString = String(data: data!, encoding: usedEncoding) {
        print("this is my string: \(myString)")
    } else {
        print("failed to decode data")
    }
})
task.resume()

Update for Swift 3:

let session = URLSession.shared
let request = URLRequest(url: URL(string: "http://hq.sinajs.cn/list=sz000609")!)
let task = session.dataTask(with: request, completionHandler: {
    (data, response, error) -> Void in

    guard let data = data else { return }

    var usedEncoding = String.Encoding.utf8 // Some fallback value
    if let encodingName = response?.textEncodingName {
        let encoding = CFStringConvertEncodingToNSStringEncoding(CFStringConvertIANACharSetNameToEncoding(encodingName as CFString))
        if encoding != UInt(kCFStringEncodingInvalidId) {
            usedEncoding = String.Encoding(rawValue: encoding)
        }
    }
    if let myString = String(data: data, encoding: usedEncoding) {
        print("this is my string: \(myString)")
    } else {
        print("failed to decode data")
    }
})
task.resume()
Ever answered 17/8, 2015 at 13:27 Comment(1)
i understand the reason, great thanks @Martin R, thanks for the answer and the good soultionMonospermous
L
3

The text you try to get is probably not UTF-8, try with another encoding, like this for example:

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

Update: read Martin R's answer for how to find the right encoding.

Longhair answered 17/8, 2015 at 13:12 Comment(4)
While it might be possible that the result was not UTF-8 encoding... I don't think this would actually result in the string being nil (versus simply unintelligible).Parsee
It seems like it is GBK and according to the list of available encodings it is probably kCFStringEncodingGB_18030_2000Spiegelman
@Parsee I just tested in a Playground, it is nil with NSUTF8StringEncoding but works with NSASCIIStringEncoding. :) Although I'm not sure this ASCII encoding is the right one for OP, it doesn't return nil anymore with it.Longhair
@nhgrif: NSString(data:encoding:) does return nil if the data is not valid in the specified encoding, and data in GBK encoding is unlikely to be valid UTF-8.Ever

© 2022 - 2024 — McMap. All rights reserved.