Swift: NSData(contentsOfURL) crashing on XCode 6.1 - swift

Before upgrading to XCode6.1 I was using the method NSData.dataWithContents() and it was working perfectly all the images were downloading. Today I have updated to XCode 6.1 and it forces me to use the function like this:
NSData(contentsOfURL: NSURL(string: completeUrl)!)!
and when I run the application it crashes on it with message:
fatal error: unexpectedly found nil while unwrapping an Optional value
I have tried many things but nothing works. I am looking for any simple alternative for this to download images from a given URL.

Since the initalization of NSURL may fail due to several reasons you should better use it this way:
if let url = NSURL(string: completeUrl) {
if let data = NSData(contentsOfURL: url) { // may return nil, too
// do something with data
}
}

More better way to download files is:
let request:NSURLRequest = NSURLRequest(URL: NSURL(string: completeUrl)!)
NSURLConnection.sendAsynchronousRequest(request, queue: NSOperationQueue.mainQueue(), completionHandler: { (response:NSURLResponse!, imageData:NSData!, error:NSError!) -> Void in
var filePath:String = pathString + "/" + fileName
imageData.writeToFile(filePath, atomically: true)
})
It is working very nicely and also it gives you more control on the request.

Related

Swift HTTP Request Completion Block not Working Properly

I have a weird problem with HTTP requests in Swift. I have the following simple code:
let session = URLSession.shared
let url = URL(string: "https://jsonplaceholder.typicode.com/posts")!
let task = session.dataTask(with: url, completionHandler: { data, response, error in
// Check the response
print(error)
print(response)
})
task.resume()
Running this code in a Xcode playground outputs the print statements. However, executing it in a standard Xcode project does not give any output.
I wonder if I am missing something in my code or if something is wrong with my Xcode setup.
Thanks in advance!
Edit:
Here's a screenshot of Xcode
As Tarun indicated, your executable is exiting before your call can be made. One way you can wait before exiting is to use a DispatchGroup like the following.
let session = URLSession.shared
let url = URL(string: "https://jsonplaceholder.typicode.com/posts")!
let group = DispatchGroup()
group.enter()
let task = session.dataTask(with: url, completionHandler: { data, response, error in
// Check the response
print(error)
print(response)
group.leave()
})
task.resume()
group.wait()
Looking at this screenshot -
It doesn't seem like any part of your code is executing at all. There's no entry point defined.
You can try following -
#main
struct NewApp {
static func main() {
// Paste all of your code here
// Put breakpoints and inspect what you want
}
}

Strange error nw_protocol_get_quic_image_block_invoke dlopen libquic failed

I'm new to swift and iOS in general, please keep that in mind.
I get this error when opening the CFReadStream. It does not matter if I open the read or write streams, the app always fails.
var readStream: Unmanaged<CFReadStream>?
var writeStream: Unmanaged<CFWriteStream>?
let host: CFString = NSString(string: hostIP)
let port: UInt32 = UInt32(self.VNCport)
self.password = password
CFStreamCreatePairWithSocketToHost(kCFAllocatorDefault, host, port, &readStream, &writeStream)
inputStream = readStream!.takeRetainedValue()
outputStream = writeStream!.takeRetainedValue()
if readStream == nil {
print("Erro read")
}
if writeStream == nil {
print("Erro write")
}
inputStream!.delegate = self
outputStream!.delegate = self
inputStream!.schedule(in: RunLoop.main, forMode: RunLoop.Mode.default)
outputStream!.schedule(in: RunLoop.main, forMode: RunLoop.Mode.default)
inputStream!.open()
outputStream!.open()
I made a clean project with just this function and a Button, the result is the same. No quic lib is used in the project.
Can someone help?
I faced the same error in a different context, in XCode 12.0.1 too. It might not be related, but I suspect its an issue with accessing the run loop of the main thread. I was just trying out some introductory code I found online, and faced the same issue, so this is a bug, rather than a problem with your code. Here's how you can get a piece of code that has the same issue:
git clone git#github.com:BestKora/CS193P-Fall-2017-Demo-iOS12.git
cd "CS193P-Fall-2017-Demo-iOS12/Cassini L10"
xed . # this opens XCode (CLI tool stands for XCode editor)
Having said that, by rewriting the code, I was able to prevent this issue. Maybe you can find something amongst the code below to fix your specific issue:
Specifically, instead of using the following (DispatchQueue.global)
private func fetchImage() {
if let url = imageURL {
spinner.startAnimating()
DispatchQueue.global(qos: .userInitiated).async { [weak self] in
let urlContents = try? Data(contentsOf: url)
DispatchQueue.main.async {
if let imageData = urlContents, url == self?.imageURL {
self?.image = UIImage(data: imageData)
}
}
}
}
}
I use URLSession.shared.dataTask, and this error no longer happens:
private func fetchImage() {
print("fetching image")
if let url = imageURL {
let task = URLSession.shared.dataTask(with: url) {(data, response, error) in
guard let data = data else {
return
}
// maybe try dispatch to main
DispatchQueue.main.async {
self.imageView.image = UIImage(data: data)
}
}
task.resume()
}
}
I had same issue in an Widget Target, but solved it by adding "public" to the variables.
Fixed struct is shown below.
struct LastCommitEntry: TimelineEntry {
public let date: Date
public let commit: Commit
}
This is just a Simulator message. It won't appear on a real device, and it doesn't affect the behavior of your app, so ignore it.
I was getting this issue in url session.
Thank you
Restarting my simulator did the trick.
For me, it started working when I encoded the data using String(data: safeData, encoding: .utf8) line:
if let safeData = data {
let dataString = String(data: safeData, encoding: .utf8)
print(dataString!)
}
In my case it was a problem with the model. I was working with Codable Model but it wasn't parsing the data properly. When I used the simulator the error was there but when I used my device it disappeared, neverthelesss, the collection view wasn't showing. When I change my model the error was corrected.
You'll need to adopt that specific delegate you're using in your class.
Like in below example:
class ViewController: UIViewController, UITextFieldDelegate
And don't forget to set your current class as the delegate, like below (for my own case):
IBOutlet weak var searchTextField: UITextField!
searchTextField.delegate = self

How do you test a URL and get a status code in Swift 3?

I'm using the most recent version of Xcode (8.1 at time of writing), which uses Swift 3.0.
All I'm trying to do is take a string, convert it to a URL and test that URL to see if it gives me a 404 error. I've been able to make a URL and URLRequest by using:
let url = URL(string: fullURL)
let request = URLRequest(url: url!)
but I've found myself unable to get anything working beyond that. I've searched around for help, but most, if not all of it, is written in Swift 2.0, which I've tried to convert to no avail. It seems that even if you change the naming convention to remove the NS prefix, that isn't enough. I tried using:
let response: AutoreleasingUnsafeMutablePointer<URLRequest> = nil
but that gives me an error that "fix-it" makes worse by sticking question marks and semi-colons everywhere.
Apple's documentation isn't helping me much, either. I'm seriously at a loss.
Does anybody know how to correctly set up and test a URL for 404 status in Swift 3.0?
try this out to give you the status codes of the responses - 200, 404 etc:
let url = URL(string: fullURL)
let task = URLSession.shared.dataTask(with: url!) { _, response, _ in
if let httpResponse = response as? HTTPURLResponse {
print(httpResponse.statusCode)
}
}
task.resume()
You could also do the same, simply replacing the with: url! to use the request var as you defined in your example e.g. let task = URLSession.shared.dataTask(with: request) {...} But in this example I don't think you need to really.
Simple example:
let url = // whatever
let session = URLSession.shared
let task = session.downloadTask(with:url) { loc, resp, err in
let status = (resp as! HTTPURLResponse).statusCode
print("response status: \(status)")
}
task.resume()
Here is one more example from delegate method
public func urlSession(_ session: URLSession, dataTask: URLSessionDataTask, didBecome downloadTask: URLSessionDownloadTask){
let responseStatusCode = (dataTask.response as! HTTPURLResponse).statusCode
}
Here is the example https://github.com/ankitthakur/SwiftNetwork/blob/master/Sources/Shared/SwiftNetwork.swift

Swift: How to download synchronously?

I am using following code, to download some files:
let url = NSURL(string:"https://www.example.org/")!
let task = NSURLSession.sharedSession().dataTaskWithURL(url) { (data, response, error) in
if error != nil {
NSLog("%#", "Error: \(error)");
return
}
NSLog("Loaded %i bytes", data!.length)
}
task.resume()
I want to process some of the files and quit my application after downloading. Therefore I need to know, when the download process is finished. The best would be, if there is a way to do this synchronously (no problem, if UI is blocked - it is just a spash screen with a progressbar). But as far as I understood this topic after some research, this is not possible in Swift any more...
I did wrap this code in a function, therefore I can't just add some code after the NSLog statement. What I need to know is: When did the last file finish downloading? How can I retrive this information?
EDIT: This code did work for me (but be aware, its deprecated!):
// download file synchonously ////////////////////////////////////////////////////
func downloadSync(fromURL: String, toPath: String) {
let request = NSURLRequest(URL: NSURL(string: fromURL)!)
var response: NSURLResponse?
do {
let data = try NSURLConnection.sendSynchronousRequest(request, returningResponse: &response)
data.writeToFile(toPath, atomically: true)
} catch {
print("Error while trying to download following file: " + fromURL)
}
}
After you invoke task.resume(), the download starts.
When the download does complete (or an error is received) the code
inside the { } following dataTaskWithURL is called. That's a closure and it's called asynchronously.
let task = NSURLSession.sharedSession().dataTaskWithURL(url) { (data, response, error) in
// This code is executed asynchronously after data has been received
}
task.resume()
Inside the closure you receive 3 params:
data: the NSData you requested
response: the whole NSURLResponse
error: an NSError object
These 3 values are optional, so could be nil.
E.g. error could be populated and data could be nil.
The synchronous way [DEPRECATED in iOS 9]
This approach has been deprecated in iOS 9 and you should NOT use it, however here's the code
var response: NSURLResponse?
var error: NSError?
let urlData = try NSURLConnection.sendSynchronousRequest(request, returningResponse: &response)

Snap to Roads in Swift

I am trying to implement a method that uses Googles snap to roads API however I have been unable to achieve any results.
I was able to successfully implement the directions API in to my Swift project using
https://maps.googleapis.com/maps/api/directions/json?origin=xyz
let request = NSURLRequest(URL: NSURL(string:directionURL)!)
let session = NSURLSession.sharedSession()
session.dataTaskWithRequest(request,
completionHandler: {(data: NSData!, response: NSURLResponse!, error: NSError!) in
if error == nil {
let object = NSJSONSerialization.JSONObjectWithData(data, options: nil, error: nil) as! NSDictionary
println(object)
let routes = object["routes"] as! [NSDictionary]
for route in routes {
println(route["summary"])
}
dispatch_async(dispatch_get_main_queue()) {
//update your UI here
}
}
else {
println("Direction API error")
}
}).resume()
however if the GPS coordinates are even slightly different I get an entirely different result.
What I am trying to do is plot a users path the same each time even if the start/end coordinates a slightly different.
The error I am getting is
fatal error: unexpectedly found nil while unwrapping an Optional value
Any suggestions?
Thanks
EDIT:
I am trying this but this is what is causing the error
func directionAPITest() {
let directionURL = "https://roads.googleapis.com/v1/snapToRoads?path=-35.27801,149.12958|-35.28032,149.12907|-35.28099,149.12929|-35.28144,149.12984|-35.28194,149.13003|-35.28282,149.12956|-35.28302,149.12881|-35.28473,149.12836&interpolate=true&key=xyz"
let request = NSURLRequest(URL: NSURL(string:directionURL)!)
let session = NSURLSession.sharedSession()
}
I was able to resolve this after finding this post NSURL found nil while unwraping an Optional value
Basically had to escape the string.