error in swift when using loadDataFromURL in Xcode 8.3 - swift

I am testing this code from Ray Wenderlich to download data from URL. I got it working, but I updated to Xcode 8.3 and now suddenly it does not work any longer. I got the advise back that my problem has already been resolved in the following link SWIFT: Error EXC_BAD_INSTRUCTION, however, when adding the try! option or adding a do-catch as suggested, this did not make the error go away. Here is the code again:
class func loadDataFromURL(_ url: URL, completion:#escaping (_ data: Data?, _ error: NSError?) -> Void) {
let session = URLSession.shared
// Use NSURLSession to get data from an NSURL
let loadDataTask = try! session.dataTask(with: url, completionHandler: { (data: Data?, response: URLResponse?, error: NSError?) -> Void in
if let responseError = error {
completion(nil, responseError)
print("something went wrong 1")
//activityIndicator.stopAnimating()
} else if let httpResponse = response as? HTTPURLResponse {
if httpResponse.statusCode != 200 {
let statusError = NSError(domain:"com.raywenderlich", code:httpResponse.statusCode, userInfo:[NSLocalizedDescriptionKey : "HTTP status code has unexpected value."])
completion(nil, statusError)
} else {
completion(data, nil)
//activityIndicator.stopAnimating()
}
}
} as! (Data?, URLResponse?, Error?) -> Void) //error is thrown here!!
loadDataTask.resume()
}
}
When I run the code I get the error code in the last line: "Thread 1: EXEC_BAD_INSTRUCTION(code=EXC_I386_INVOP,subcode=0x0)"

I had this problem when I tried to parsing data Asynchronously it got rid of the error and worked fine. I'm not sure but it may solve your problem,too.

Related

How to handle XPC connection interrupted in URLSession.shared.dataTask

This is my code, by which I am trying to catch the error, when server is down:
let task = URLSession.shared.dataTask(with: request) { (data: Data?, response: URLResponse?, error: Error?) in
if error != nil
{
self.displayMessage(userMessage: "Could not successfully perform this request. Please check yourr internet connection.")
print("error=\(String(describing: error))")
return
}
do {
let json = try JSONSerialization.jsonObject(with: data!, options: .mutableContainers) as? NSDictionary
if let parseJSON = json {
if parseJSON["errorMessageKey"] != nil
{
self.displayMessage(userMessage: parseJSON["errorMessage"] as! String)
return
}
...
} else {
self.displayMessage(userMessage: "Could not successfully perform this request. Please try again later")
}
} catch {
self.displayMessage(userMessage: "Could not successfully perform this request. Please try again later")
print(error)
}
}
task.resume()
But in console I get "XPC connection error", instead of displaying alert.
How can I display Alert, when this error occures?
My environment:
Swift: 5
Xcode: 11.5
Target deployment: 13.4
Assuming displayMessage has no problem as you have not provided the code.
I would suggest you call the code which has the UIKit API, on the main thread. As the dataTask completion block is always called on a background thread. I would suggest you while calling the function which further has the code related to UIKit should always run on the main thread
Use UIKit classes only from your app’s main thread or main dispatch
queue, unless otherwise indicated. This restriction particularly
applies to classes derived from UIResponder or that involve
manipulating your app’s user interface in any way.
Have a look at the updated code snippet.
let task = URLSession.shared.dataTask(with: request) { (data: Data?, response: URLResponse?, error: Error?) in
// It ensure rest code placed inside run on the main thread. I assume displayMessage function having the code related to UIKit framework.
DispatchQueue.main.async {
if error != nil
{
self.displayMessage(userMessage: "Could not successfully perform this request. Please check yourr internet connection.")
print("error=\(String(describing: error))")
return
}
do {
let json = try JSONSerialization.jsonObject(with: data!, options: .mutableContainers) as? NSDictionary
if let parseJSON = json {
if parseJSON["errorMessageKey"] != nil
{
self.displayMessage(userMessage: parseJSON["errorMessage"] as! String)
return
}
} else {
self.displayMessage(userMessage: "Could not successfully perform this request. Please try again later")
}
} catch {
self.displayMessage(userMessage: "Could not successfully perform this request. Please try again later")
print(error)
}
}
}
task.resume()

ambiguous reference to member datatask swift Xcode 8

I just updated my Xcode and have been trying to learn more about it. This is my code for Collection View Cell. I'm trying to get data from URL but I've been annoyed with this error. I tried all the solutions in here but they have different function structure. Also other solutions didn't work.
import UIKit
class PersonCell: UICollectionViewCell {
#IBOutlet weak var personImage : UIImageView!
func ConfigureCell (imgURL : String)
{
}
func DownloadImage ( url : NSURL)
{
}
func GetDatafromURL (URL : NSURL , completion : #escaping (( _ data : NSData? , _ response : URLResponse? , _ error : NSError?) -> Void))
{
URLSession.shared.dataTask(with: URL) { (data , response , error) in
completion (data , response, error)
}.resume()
}
}
the code that worked in the tutorial video is something like this
func GetDatafromURL (URL : NSURL , completion : (( data : NSData? , response : NSURLResponse? , error : NSError?) -> Void))
{
NSURLSession.sharedSession.dataTaskWithURL( URL) { (data , response , error) in
completion(data : data , responce : response, error : error)
}.resume()
You can convert your NSURL to a URL using .absoluteURL
guard let url = URL.absoluteURL else { return }
URLSession.shared.dataTask(with: url) { (data, response, error) in
//
}.resume()
UPDATE
Your completion block has the wrong types. You're using NSData instead of Data and NSError instead of Error. Here's an example of what it should look like below.
func getData(from url: URL, completion: #escaping (_ data: Data?, _ response: URLResponse?, _ error: Error?) -> Void)
{
URLSession.shared.dataTask(with: url) { data, response, error
completion(data, response, error)
}.resume()
}
Please check the latest reference.
func dataTask(with: URL, completionHandler: (Data?, URLResponse?, Error?) -> Void)
Declaration
func dataTask(with url: URL,
completionHandler: #escaping (Data?, URLResponse?, Error?) -> Void) -> URLSessionDataTask
In Swift 3, the completionHandler of dataTask(with:completionHandler:) takes 3 arguments with types Data?, URLResponse? and Error?. So, your method's completion, which is of type (NSData?,URLResponse?,NSError?) -> Void cannot be applied.
And it takes URL as its first parameter.
(Thanks to vadian, he suggested all needed things here.)
So, your GetDatafromURL needs to be something like this:
func GetDatafromURL(url: URL, completion: #escaping ((_ data: Data?, _ response: URLResponse?, _ error: Error?) -> Void))
{
URLSession.shared.dataTask(with: url) { (data, response, error) in
completion (data , response, error)
}.resume()
}

Many problems with Swift3: cannot understand new syntax for completion handlers

Yesterday I updated to new Mac OS X Sierra and XCode 8 which forced me to update to Swift 3.0 syntax. In my app I have many functions like the following:
fileprivate func requestFisheFieldWithHandler(_ url:String, completionHandler: #escaping (_ success: NSDictionary?, _ error: NSError?) -> Void) {
let configuration = URLSessionConfiguration.default
let url: URL = URL(string: url)!
let urlRequest: URLRequest = URLRequest(url: url)
let session = URLSession(configuration: configuration)
let task = session.dataTask(with: urlRequest, completionHandler: { (data: Foundation.Data?, response: URLResponse?, error: NSError?) -> Void in
if (error != nil) {
//print(error?.code)
//print(error)
completionHandler(success: nil, error: error)
}
else {
do {
let responseJSON = try JSONSerialization.jsonObject(with: data!, options: JSONSerialization.ReadingOptions()) as! [String: String]
completionHandler(success: responseJSON, error:nil)
}
catch let error as NSError {
completionHandler(success: nil, error:error)
}
}
} as! (Data?, URLResponse?, Error?) -> Void)
task.resume()
}
and I get this error:
"Cannot convert value of type '(Data?, URLResponse?, Error?) -> Void' to expected argument type '(Data?, URLResponse?, Error?) -> Void'"
Moreover, I also used many associative arrays to collect data from downloaded JSON file, like the following:
for comune in response! {
self.comuni.append(comune["nome"] as! String)
self.comuniWithID[comune["nome"] as! String] = Int(comune["idcomune"] as! String)
}
DispatchQueue.main.async {
self.myPicker.reloadComponent(1)
}
and another error I get is:
"Type 'NSFastEnumerationIterator.Element' (aka 'Any') has no subscript members"
Please, would someone help me to correct them? Because I cannot understand what they mean and my app will be published next 30th September...
The most significant change is that all parameter labels in closures have been removed in Swift 3.
This is your code Swift 3 compatible.
As always, do not cast a Swift collection type to a Foundation counterpart. You will throw away all type information.
And don't use the annotations in the completion block return values, the compiler can infer the types. If you need to look up the actual types ⌥-click on the symbol.
fileprivate func requestFisheFieldWithHandler(_ url:String, completionHandler: #escaping ([String: String]?, NSError?) -> Void) {
let configuration = URLSessionConfiguration.default
let url: URL = URL(string: url)!
let urlRequest = URLRequest(url: url)
let session = URLSession(configuration: configuration)
let task = session.dataTask(with: urlRequest) { (data, response, error) -> Void in
if (error != nil) {
completionHandler(nil, error as NSError?)
}
else {
do {
let responseJSON = try JSONSerialization.jsonObject(with: data!, options: JSONSerialization.ReadingOptions()) as! [String: String]
completionHandler(responseJSON, nil)
}
catch let error as NSError {
completionHandler(nil, error)
}
}
}
task.resume()
}
Regarding the second error you have to cast response! to something more meaningful than Any, I guess ... in response as! [[String:Any]]
The completion handler of dataTask(with:completionHandler:) in Swift 3 is changed to completionHandler: #escaping (Data?, URLResponse?, Error?) -> Void so use Error instead of NSError.
let task = session.dataTask(with: urlRequest, completionHandler: { (data: Data?, response: URLResponse?, error: Error?) -> Void in
For more about completion Handler check Apple Documentation.
For your error
Type 'NSFastEnumerationIterator.Element' (aka 'Any') has no subscript members"
You need to specify the type of your response to [[String:Any]] then all goes to normal.
if let array = response as? [[String: Any]] {
for comune in array {
self.comuni.append(comune["nome"] as! String)
self.comuniWithID[comune["nome"] as! String] = Int(comune["idcomune"] as! String)
}
}

Swift 2.0 : Cannot invoke with an argument list of type... (HTTP Request)

Since I upgraded to Xcode 7 beta I have an error that I can't fix.
Here's the full code from my DataManager.swift
import Foundation
var TopAppURL:String = String()
var numberAsked:String = String()
class DataManager {
class func getInfo(ID : String){
TopAppURL = "http://sweetapi.com/?=\(ID)"
numberAsked = ID
}
class func loadDataFromURL(url: NSURL, completion:(data: NSData?, error: NSError?) -> Void) {
var session = NSURLSession.sharedSession()
// Use NSURLSession to get data from an NSURL
let loadDataTask = session.dataTaskWithURL(url, completionHandler: { (data: NSData!, response: NSURLResponse!, error: NSError!) -> Void in
if let responseError = error {
completion(data: nil, error: responseError)
} else if let httpResponse = response as? NSHTTPURLResponse {
if httpResponse.statusCode != 200 {
var statusError = NSError(domain:"com.raywenderlich", code:httpResponse.statusCode, userInfo:[NSLocalizedDescriptionKey : "HTTP status code has unexpected value."])
completion(data: nil, error: statusError)
} else {
completion(data: data, error: nil)
}
}
})
loadDataTask.resume()
}
class func getDataFromSweetApiOk(success: ((IDdata: NSData!) -> Void)) {
//1
print("DataManager loads \(TopAppURL)")
loadDataFromURL(NSURL(string: TopAppURL)!, completion:{(data, error) -> Void in
//2
if let urlData = data {
//3
success(IDdata: urlData)
}
})
}
}
So I got this error : "Cannot invoke 'dataTaskWithURL' with an argument list of type '(NSURL, completionHandler: (NSData!, NSURLResponse!, NSError!) -> Void)'"
I searched everywhere how to fix this but like Swift 2.0 is very new, I didn't found any solution.
func dataTaskWithURL(_ url: NSURL,
completionHandler completionHandler: ((NSData!,
NSURLResponse!,
NSError!) -> Void)?) -> NSURLSessionDataTask
has changed to
func dataTaskWithURL(_ url: NSURL,
completionHandler completionHandler: (NSData?,
NSURLResponse?,
NSError?) -> Void) -> NSURLSessionDataTask?
in iOS9. The completionHandler no longer is optional, and all parameters in the completionHandler are now optionals instead of implicitly unwrapped optionals.
Now, to help with this in future changes to the optional system, try to avoid (data: NSData!, response: NSURLResponse!, error: NSError!) -> Void in, you can simply use data, response, error in and then option-click for more details.
This will remove bloat from your code, and thus improve readability.
To solve your problem in the comments, check out this question.

Swift crash when NSURLConnection.sendAsynchronousRequest returns an error

Using the following code works fine UNLESS there is an error, then
NSURLConnection.sendAsynchronousRequest(request, queue: NSOperationQueue.mainQueue(), completionHandler: {(response: NSURLResponse!,data: NSData!, error: NSError!) -> Void in
if error? {
...
}
else {
...
}
when is crashes with
"EXC_BAD_INSTRUCTION (code=EXC_I386_INVOP, subcode=0"
on the if error? line.
Does anybody know why ?
Now NSURLConnection is deprecated now you should use NSURLSession instead still I am posting an example of NSURLConnection
in your code you are forcefully unwrap value of error: NSError! response: NSURLResponse!,data: NSData! is creating problem
let request = URLRequest(url: URL.init(string: "yourURL")!)
NSURLConnection.sendAsynchronousRequest(request, queue: OperationQueue.main) { (request, data, error) in
// Here you can check error with guard and data also
}
Hope it is helpful to you