NSData(contentsOf:,options:) works on the simulator, but not on the device

What is wrong with NSData(contentsOf:,options:) on the device?

On the Simulator, i can read the url and get the JSON content, but when i run on the actual Apple Watch, i get the following error:


Error 3: Error Domain=NSCocoaErrorDomain Code=256 "Could not open file “******”." UserInfo={NSURL=http://******}


Here is my code:


let url = NSURL(string: "http://some.website")
var mainArray: Array<Dictionary<String, AnyObject>> = []
do{
     let data: Data = try Data(contentsOf: url!)
     let dictionary: Any? = try JSONSerialization.jsonObject(with: data as Data, options: JSONSerialization.ReadingOptions())
     if let dictionary = dictionary as? Dictionary<String, AnyObject> {
          mainArray = dictionary["data"] as! Array<Dictionary<String, AnyObject>>
          mainArray = mainArray.reversed()
     } else {
          print("Error 1: not a valid JSON")
     }
} catch {
     print("Error 2: \(error)")
}


I tried with URLSession and it works on the device, but it's sooooooo much slower.

Replies

Last I checked,

Data(contentsOf:options:)
uses NSURLConnection internally, and NSURLConnection is not available on watchOS. You will have to use NSURLSession here.

I tried with URLSession and it works on the device, but it's sooooooo much slower.

So much slower than what? How can you compare speeds between the two implementations when one of those implementations doesn’t work?

Share and Enjoy

Quinn “The Eskimo!”
Apple Developer Relations, Developer Technical Support, Core OS/Hardware

let myEmail = "eskimo" + "1" + "@apple.com"

Hi Eskimo,


Just my little two cents:

So much slower than what? How can you compare speeds between the two implementations when one of those implementations doesn’t work?




Testing on the simulator weirdly works for both, so it's possible to test both and compare speed.

Also, contentsOf is synchrone (I mean, it returns something on the same execution loop), while NSURLSession is async and you'll have to wait.


One question thought, is it normal that updated functions like Data/String's "contentsOf:url" are still using a deprecated method like NSURLConnection internally?

And if this latter isn't available on watchOS, isn't it more effective to mark it as unavailable for watchOS in the fundations? Or is this a "bug"?


Thank you.

Testing on the simulator weirdly works for both …

Just FYI, the reason it works on the simulator is that the simulator does not enforce sandbox restrictions, and it’s the sandbox that’s prevent NSURLConnection from working on the device.

so it's possible to test both and compare speed.

Right, but that’s not a realistic comparison because the request ends up being done directly by your process rather than being bounced to a secondary process (and possibly the iPhone) as it would on a real device.

Also, contentsOf is synchrone (I mean, it returns something on the same execution loop), while NSURLSession is async and you'll have to wait.

Right, but that’s the right option anyway. There’s two possibilities here:

  • You’re doing the

    Data(contentsOf:)
    on the main thread, and that’s not going to end well. QA1693 Synchronous Networking On The Main Thread explains this.
  • You’re doing the

    Data(contentsOf:)
    on a secondary thread, which is just wasting memory (the thread consumes memory to no useful effect, it’s just blocked waiting for the network). This is particularly problematic on watchOS, where the hardware doesn’t have a lot of headroom.

One question thought, is it normal that updated functions like Data/String's "contentsOf:url" are still using a deprecated method like NSURLConnection internally?

I’m not sure what you mean by “normal”. Clearly this is suboptimal, but that’s not quite the same thing (-:

If I had my druthers I’d change these

contentsOf
methods to fail if given a network URL. Support for network URLs made some degree of sense when it was originally introduced during the earlier days of Mac OS X, but it makes very little sense on our current platforms.

And if this latter isn't available on watchOS, isn't it more effective to mark it as unavailable for watchOS in the fundations?

Alas, we can’t mark it as unavailable because it is available and recommended for accessing file system URLs.

Share and Enjoy

Quinn “The Eskimo!”
Apple Developer Relations, Developer Technical Support, Core OS/Hardware

let myEmail = "eskimo" + "1" + "@apple.com"