When I get data from server it will display fatal error
below my code
URLSession.shared.dataTask(with: myRequest, completionHandler: { (data:Data?, response:URLResponse?, error:Error?) -> Void in
DispatchQueue.main.async {
if error != nil {
}
do {
if let json = try JSONSerialization.jsonObject(with: (data)!, options: .mutableContainers) as? NSMutableDictionary {
}
}
}
let task = URLSession.shared.dataTask(with: request) { (data, response, error) in
do
{
let dict = try JSONSerialization.jsonObject(with: data!, options: .mutableContainers)
Dispatch.main.async {
// refresh ui like tableview[tableView.roloadData()] or collectionview
}
}catch{
}
}
task.resume()
You a have few errors in your code.
You are checking error for nil and deserializing json outside this check.
You are force unwrapping (!) data without checking it for nil.
You use do, but I don't see catch. Please don't use do/catch unless you really need it.
Also, I suggest you using mainThread when you already deserialized object.
URLSession.shared.dataTask(with: myRequest) { (data, _, error) -> Void in
guard let data = data else { return }
let dict = try? JSONSerialization.jsonObject(with: data, options: .mutableContainers) {
...
Dispatch.main.async {
// refresh ui
}
}
}
Related
I create a class and I'm getting an warning message when I try to cast an object as AnyObject.
The warning is: " Conditional cast from 'Any' to 'AnyObject' always succeeds "
How can I remove this warning from my file ?
Here is my code:
class WebServices
{
class func getRequest( urlString: String, successBlock :#escaping (_ response :AnyObject)->Void, errorMsg:#escaping (_ errorMessage :String)->Void )
{
var request = URLRequest(url: URL(string: urlString)!)
request.httpMethod = "GET"
let task = URLSession.shared.dataTask(with: request) { (data, urlResponse, error) in
DispatchQueue.main.async {
if(error == nil)
{
do {
// Here is the warning
let responseJSON = try JSONSerialization.jsonObject(with: data!, options: .mutableContainers) as? AnyObject
guard let _ = responseJSON else {
errorMsg("Some error has been occurred!")
return
}
successBlock(responseJSON!)
}
catch
{
errorMsg("Some error has been occurred!")
}
}
else
{
errorMsg(error!.localizedDescription)
}
}
}
task.resume()
}
}
Thank you guys for your time if you are reading this !
This function
let responseJSON = try JSONSerialization.jsonObject(with: data!, options: .mutableContainers) as? AnyObject
returns Any and you cast it to AnyObject which nearly the same , it's better to cast to the expected json content whether it's an array or dictionary
let responseJSON = try JSONSerialization.jsonObject(with: data!) as? [String:Any]
Or
let responseJSON = try JSONSerialization.jsonObject(with: data!) as? [Any]
and change the completion accordingly
Iam getting an error while i try to send the POST request in swift 3. Any one please suggest me the correct syntax for URLSession.shared method in swift 3. this is what i tried. iam new here.
let task = URLSession.shared.dataTask(with: request, completionHandler: {
(data, response, error) in
if error != nil{
print("error");
return
}
do{
let myjson = try JSONSerialization.jsonObject(with: data!, options: .mutableContainers) as? NSDictionary
if let parsejson = myjson{
var msg: String!
msg = parsejson["message"] as! String?
print(msg)
}catch error {
print ("")
}
}
})
task.resume().
Here's working URLSession.shared code. I don't have your URL so I used one that is online, free, and produces JSON:
let someURL = URL(string:"https://jsonplaceholder.typicode.com/posts/2")!
let request = URLRequest(url: someURL)
let task = URLSession.shared.dataTask(with: request) { (data, response, error) in
if error != nil {
print("error")
return
}
guard let data = data else {
print("No data")
return
}
do {
if let myjson = try JSONSerialization.jsonObject(with: data, options: .mutableContainers) as? Dictionary<String,Any> {
if let title = myjson["title"] {
print("Title was \"\(title)\"")
}
}
} catch {
print("Error parsing JSON: \(error)")
}
}
task.resume()
This outputs Title was "qui est esse" for me.
I have created one function using completion handler in NSObject class for consumption of web services. However I am not getting a way to call that function with handler return.
func getUser(url:String, completionHandler: #escaping (NSDictionary?, NSError?) -> ()) {
let config = URLSessionConfiguration.default // Session Configuration
let session = URLSession(configuration: config) // Load configuration into Session
let url = URL(string: url)!
let task = session.dataTask(with: url, completionHandler: {
(data, response, error) in
if error != nil {
completionHandler(nil, error as NSError?)
} else {
do {
if let json = try JSONSerialization.jsonObject(with: data!, options: .allowFragments) as? [NSDictionary: Any] {
completionHandler(json as NSDictionary?,nil)
}
} catch {
print("error in JSONSerialization")
}
}
})
task.resume()
}
You should make sure that your completionHandler is called in every cases: for example, when the JSONSerialization throws, you catch and print the error, but you're not calling your completionHandler. The same if the JSON result is nil
ADDING
You can handle it in this way:
do {
let json = try JSONSerialization.jsonObject(with: data!, options: .allowFragments) as? [NSDictionary: Any]
completionHandler(json,nil)
} catch(let error) {
print(error)
completionHandler(nil, error)
}
I have written a function for a URL request. This contains a completion handler that returns a dictionary of [String: AnyObject] that is fetched from the URL.
The code for this is:
func getDataAsyncFromURLRequest(url: NSURL, completion: ([String : AnyObject]) -> ()) {
let request = NSMutableURLRequest(URL: url)
let session = NSURLSession.sharedSession()
let task = session.dataTaskWithRequest(request) { (data, response, error) -> Void in
if error != nil {
print("error=\(error)")
return
}
else {
let datastring = NSString(data: data!, encoding: NSUTF8StringEncoding)
if let data = datastring!.dataUsingEncoding(NSUTF8StringEncoding) {
do {
let json = try NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions()) as! [String : AnyObject]
completion(json)
} catch {
print("json error: \(error)")
}
}
}
}
task.resume()
}
In some cases, however, I will receive an array of [String : AnyObject] and not the dictionary. So instead of making a duplicate function that takes the array of dictionaries as parameter for the completion handler, I though it was possible to do like this
func getDataAsyncFromURLRequest<T>(url: NSURL, completion: (T) -> ()) {
// code here
}
... and then do like this let json = try NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions()) as! T, but that gives me this error: Cannot invoke 'getDataAsyncFromURLRequest' with an argument list of type '(NSURL, completion: (_) -> ())'
What would be the best way to make the completion handler accept a parameter with a type decided at runtime, if possible at all?
It's very easy why don't you use AnyObject
func getDataAsyncFromURLRequest(url: NSURL, completion: (AnyObject) -> ()) {
let request = NSMutableURLRequest(URL: url)
let session = NSURLSession.sharedSession()
let task = session.dataTaskWithRequest(request) { (data, response, error) -> Void in
if error != nil {
print("error=\(error)")
return
}
else {
let datastring = NSString(data: data!, encoding: NSUTF8StringEncoding)
if let data = datastring!.dataUsingEncoding(NSUTF8StringEncoding) {
do {
let json = try NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions())
completion(json)
} catch {
print("json error: \(error)")
}
}
}
}
task.resume()
}
And result of JSONObjectWithData can be [AnyObject] (Array) or [String:AnyObject] and tree of those items.
So after got result, you can also check type of result in completion block
Like this
if result is [String:AnyObject]
...
else if result is [AnyObject]
...
else
//throw error : because then it is not JSON
I grabbed a version of this code from this site (thanks to Sergey A. Novitsky). However, the 'do' block is never executed so the "json" variable is always nil. What's going on? I'm using Xcode 7.0 Beta.
func getJson(url:NSURL) -> NSDictionary! {
var json:NSDictionary!
let session = NSURLSession.sharedSession()
let task = session.dataTaskWithURL(url) {
(data:NSData?, response:NSURLResponse?, error:NSError?) in
do {
json = try NSJSONSerialization.JSONObjectWithData(data!, options: .AllowFragments) as? NSDictionary
} catch let caught as NSError {
print(caught)
} catch {
// Something else happened.
let error: NSError = NSError(domain: "<Your domain>", code: 1, userInfo: nil)
print(error)
}
}
task.resume()
return json
}
As mentioned in the other answers you need a completion block like this
func getJson(url:NSURL, completion: (json:NSDictionary?, error:NSError?)->()) {
let session = NSURLSession.sharedSession()
let task = session.dataTaskWithURL(url) {
(data:NSData?, response:NSURLResponse?, error:NSError?) in
do {
let json = try NSJSONSerialization.JSONObjectWithData(data!, options: .AllowFragments) as? NSDictionary
completion(json: json, error:nil)
} catch let caught as NSError {
completion(json: nil, error:caught)
} catch {
// Something else happened.
let error: NSError = NSError(domain: "<Your domain>", code: 1, userInfo: nil)
completion(json: nil, error:error)
}
}
task.resume()
}
call the function with
getJson(NSURL(string:"http://myserver.com")!) { (json, error) -> () in
if error != nil {
print(error!)
} else {
print(json!)
// do something with the json dictionary
}
}
That's not how asynchronous functions work. json is nil when it's returned because it won't actually be set until the asynchronous completion block for dataTaskWithURL is called. To get the value out of getJson, pass in a completion block of your own and call it inside the task's, passing back the parsed JSON to your calling site.