I am doing some webscraping and am able to get the html source code off of my desired page, but I am casting it to a NSString. When I try to convert that to JSON, I get a null when I try to print it. When I print responseString2 I am seeing the source code, but as an NSString. What am I doing wrong?
let task2 = URLSession.shared.dataTask(with: request2 as URLRequest) { data2, response, error in
guard error == nil && data2 != nil else { // check for fundamental networking error
print("error2=\(error)")
return
}
if let httpStatus = response as? HTTPURLResponse , httpStatus.statusCode != 200 { // check for http errors
print("statusCode2 should be 200, but is \(httpStatus.statusCode)")
print("response2 = \(response)")
}
let responseString2 = NSString(data: data2!, encoding: String.Encoding.utf8.rawValue)
print("hthpage \(responseString2)")
if let dataFromString = responseString2?.data(using: String.Encoding.utf8.rawValue, allowLossyConversion: false){
let json = JSON(data: dataFromString)
print("JASON \(json)")
}
Don't convert data->string->data.
Try this code
and check the error if the error occurred when converting data to json.
URLSession.shared.dataTask(with: request!) { (d, response, error) in
if let data = d
{
if let str = String(data: data, encoding: String.Encoding.utf8)
{
print("data->string : " + str)
}
do
{
if let obj = try JSONSerialization.jsonObject(with: data, options: []) as? [String:AnyObject]
{
DispatchQueue.main.async {
complete(obj)
}
}
else
{
print("Http - JsonSerialization Failed, not String:AnyObject Type!!")
}
}
catch let err as NSError
{
print("Http - JsonSerialization Error")
print(err)
}
}
else
{
if error != nil
{
print("Http - URLSession.shared.dataTask Error")
print(error)
}
}
}.resume()
Related
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 need to parse JSON from 2 different URL's
let jsonUrlStr1 = "https://123"
let jsonUrlStr2 = "https://325"
guard let url1 = URL(string: jsonUrlStr1) else { return }
guard let url2 = URL(string: jsonUrlStr2) else { return }
Here I'm running session for 1st url:
URLSession.shared.dataTask(with: url1) { (data, response, err) in
if err != nil {
print("Error:\(String(describing: err))")
}
guard let data = data else { return }
do {
let myData1 = try JSONDecoder().decode(SomeJsonModel1.self, from: data)
//Some code
} catch let jsonErr {
print("Error:\(jsonErr)")
}
}.resume()//URLSession
And then again, I'm running another session for 2nd url, using the same way:
URLSession.shared.dataTask(with: url2) { (data, response, err) in
if err != nil {
print("Error:\(String(describing: err))")
}
guard let data = data else { return }
do {
let myData2 = try JSONDecoder().decode(SomeJsonModel2.self, from: data)
//Some code
} catch let jsonErr {
print("Error:\(jsonErr)")
}
}.resume()//URLSession
This code works and I get the result.
But I think there should be a more correct way to parse 2 URLs.
Please advise how to do it correctly. Thanks.
You can try using completion block like this :
func getDataFromJson(url: String, completion: #escaping (_ success: [String : Any]) -> Void) {
let request = URLRequest(url: URL(string: url)!)
let task = URLSession.shared.dataTask(with: request) { Data, response, error in
guard let data = Data, error == nil else { // check for fundamental networking error
print("error=\(String(describing: error))")
return
}
if let httpStatus = response as? HTTPURLResponse, httpStatus.statusCode != 200 { // check for http errors
print("statusCode should be 200, but is \(httpStatus.statusCode)")
print(response!)
return
}
let responseJSON = try! JSONSerialization.jsonObject(with: data, options: .allowFragments) as! [String : Any]
completion(responseJSON)
}
task.resume()
}
and call method like this :
let jsonUrlStr1 = "https://123"
let jsonUrlStr2 = "https://325"
getDataFromJson(url: jsonUrlStr1, completion: { response in
print("JSON response for url1 :: ",response) // once jsonUrlStr1 get it's response call next API
getDataFromJson(url: jsonUrlStr2, completion: { response in
print("JSON response for url2 :: ",response)
})
})
Please review my code am badly stuck on this issue.
JSON conversion is not happening & it is going into catch block & printing following error.
Error Domain=NSCocoaErrorDomain Code=3840 "JSON text did not start with array or object and option to allow fragments not set." UserInfo={NSDebugDescription=JSON text did not start with array or object and option to allow fragments not set.}
I've tried everything which is suggested here on StackOverflow but no luck.
I've trimmed my code for better understanding.
import Foundation
class Server
{
class func convertStringToDictionary(_ data: Data) -> [String:Any]?
{
do
{
let convertedDict = try JSONSerialization.jsonObject(with: data, options: []) as? [String:Any]
return convertedDict
}
catch let error as NSError
{
print(error)
}
return nil
}
class func registerUser( userInfo: String)
{
let url = URL(string: "http://132.148.18.11/missedprayers/welcome/register")!
var request = URLRequest(url: url)
request.httpMethod = "POST"
let postString = "request=" + userInfo
request.httpBody = postString.data(using: .utf8)
//----------------------------------------
let task = URLSession.shared.dataTask(with: request)
{
data, response, error in
guard let data = data, error == nil
else
{
print("error=\(error)")
return
}
if let httpStatus = response as? HTTPURLResponse, httpStatus.statusCode != 200
{
print("statusCode should be 200, but is \(httpStatus.statusCode)")
print("response = \(response)")
}
//--------------
let finalData = Server.convertStringToDictionary(data)
print(finalData)
}
task.resume()
}
func submitBtnTapped(_ sender: AnyObject)
{
let userInfoDict = [
"name":"Maaz Patel",
"phoneNum":"+91899885623",
"email":"maaz#gmail.com",
"city":"pune",
"country":"India",
"dobEnglish":"11-02-1992",
"app":"Dalail",
"aqeeda":"Sufi",
"gender":"male",
"MCCycle":""
]
//-------------------
do
{
let jsonData = try JSONSerialization.data(withJSONObject: userInfoDict, options: [] )
let jsonStr = String.init(data: jsonData, encoding: String.Encoding.utf8)
Server.registerUser(userInfo: jsonStr!)
}
catch let error as NSError
{
print(error)
}
}
}
Consider "SubmitBtnTapped" function is getting called from somewhere.
When am trying on Postman it's working also on Android same web service is working fine.
Im learning about Swift and i trying to make an HTTP request. My code is working but i dont know how to return the result of the request:
func makeRequest(request: URLRequest)->String{
let task = URLSession.shared.dataTask(with: request){data, response, error in
guard let data = data, error == nil else{
print("error=\(error)")
return
}
if let httpStatus = response as? HTTPURLResponse, httpStatus.statusCode != 200 { // check for http errors
print("statusCode should be 200, but is \(httpStatus.statusCode)")
print("response = \(response)")
}
print (data)
do {
let json = try JSONSerialization.jsonObject(with: data, options: .allowFragments)
print(json)
} catch {
print("error serializing JSON: \(error)")
}
//print("responseString = \(responseString)")
}
task.resume()
return "Something"//i need to return the json as String
}
Someone can help me please? i was trying using CompletionHanlder but all the example that i found is based on swift 2, and this causes error on my code
The completion handler's type needs to be something like this:
#escaping ({argument types...})->{result type}
#escaping is needed as the completion handler is executed later when the communication is completed.
{argument types...} needs to be the types you want to pass to the handler, so in your case, a single type String. And you usually do not use the result from the handler, so you need to specify Void (aka ()).
Thus your completion handler's type needs to be:
#escaping (String)->Void
So, your method header becomes:
(You know you need a closing parenthesis for argument list.)
func makeRequest(request: URLRequest, completion: #escaping (String)->Void)
Whole your method would be something like this:
func makeRequest(request: URLRequest, completion: #escaping (String)->Void) {
let task = URLSession.shared.dataTask(with: request) {data, response, error in
guard let data = data, error == nil else{
print("error=\(error)")
return
}
if let httpStatus = response as? HTTPURLResponse, httpStatus.statusCode != 200 { // check for http errors
print("statusCode should be 200, but is \(httpStatus.statusCode)")
print("response = \(response)")
}
print(data as NSData) //<-`as NSData` is useful for debugging
do {
let json = try JSONSerialization.jsonObject(with: data, options: .allowFragments)
print(json)
//Why don't you use decoded JSON object? (`json` may not be a `String`)
} catch {
print("error serializing JSON: \(error)")
}
//Not sure what you mean with "i need to return the json as String"
let responseString = String(data: data, encoding: .utf8) ?? ""
completion(responseString)
}
task.resume()
}
You can use it as:
makeRequest(request: request) {response in //<-`response` is inferred as `String`, with the code above.
print(response)
}
func makeRequest(request: URLRequest, completion: (result : String?)->() {
let task = URLSession.shared.dataTask(with: request){data, response, error in
guard let data = data, error == nil else{
print("error=\(error)")
return
}
if let httpStatus = response as? HTTPURLResponse, httpStatus.statusCode != 200 { // check for http errors
print("statusCode should be 200, but is \(httpStatus.statusCode)")
print("response = \(response)")
}
print (data)
do {
let json = try JSONSerialization.jsonObject(with: data, options: .allowFragments)
print(json)
} catch {
print("error serializing JSON: \(error)")
}
completion("yourResultString")
//print("responseString = \(responseString)")
}
task.resume()
}
to call it
makeRequest(request: request) { (result : String?) in
if let result = result {
print("got result: \(result)")
}
You can't "return" the result of the request. By the time you have a result your makeRequest function has already returned to its caller. You should:
Change makeRequest to not return anything, because there's no
point
Replace the commented-out print statement with code that does
something with the responseString result.
I have to call a webservice from getResonse(url) then i want to return json . I am unable how to return json in complete handler . They give me error Unexpected non void return value in void function Please help.Any help would be apperciated. Thanks in Advance
func GetStation(url : String) {
var dict = NSDictionary()
dict = getResonse(url)
}
func getResonse(myUrl:NSString) ->NSDictionary
{
let request = NSMutableURLRequest(URL: NSURL(string: myUrl as String)!, cachePolicy: NSURLRequestCachePolicy.ReloadIgnoringCacheData, timeoutInterval: 30)
let session = NSURLSession.sharedSession()
request.setValue("application/x-www-form-urlencoded", forHTTPHeaderField: "Content-Type")
request.HTTPMethod = "GET"
let task = session.dataTaskWithRequest(request) { data, response, error in
guard data != nil else{
return
}
do {
if let json = try NSJSONSerialization.JSONObjectWithData(data!, options: []) as? NSDictionary {
print(json)
if (data == nil)
{
return nil
error
}
else
{
return json
error
}
}else {
let jsonStr = NSString(data: data!, encoding: NSUTF8StringEncoding) // No error thrown, but not NSDictionary
print("Error could not parse JSON: \(jsonStr)")
}
} catch let parseError {
print(parseError) // Log the error thrown by `JSONObjectWithData`
let jsonStr = NSString(data: data!, encoding: NSUTF8StringEncoding)
print("Error could not parse JSON: '\(jsonStr)'")
}
}
task.resume()
}
This is merely a coding error (possibly due to braces being all over the place).
In you completion handler, you have 3 forced exits two of which return a value and one that doesn't.
from the "guard data ..." --> else { return }
in the do { ... return nil ... or return json ... }
from the error message I gather that the later two returns are incorrect.
You are inside the dataTaskWithRequest: of NSUrlSession which returns
func dataTaskWithRequest(request: NSURLRequest, completionHandler: (NSData?, NSURLResponse?, NSError?) -> Void) -> NSURLSessionDataTask
It returns Void inside the block. So it's showing an error.