How to avoid "Error Domain=NSCocoaErrorDomain Code=3840" in Swift? - ios

I keep getting this particular error when trying to parse a JSON response in Swift:
Error Domain=NSCocoaErrorDomain Code=3840 "No value." UserInfo={NSDebugDescription=No value.}
Code:
let dict = [
"phone": phone,
"firstname": "\(String(describing: firstName))",
"lastname": "\(String(describing: lastName))"
]
as [String: Any]
if let jsonData = try? JSONSerialization.data(withJSONObject: dict, options: []) {
var request = URLRequest(url: URL(string: "\(config.baseURL)employee")!)
request.httpMethod = "POST"
request.addValue("application/json", forHTTPHeaderField: "Content-Type")
request.httpBody = jsonData
request.timeoutInterval = 30.0
let task = URLSession.shared.dataTask(with: request) { data, response, error in
if error != nil {
DispatchQueue.main.async {
self.alertController.singleButtonAlertController("Error", (error?.localizedDescription)!, self, self.defaultAction)
return
}
}
guard let data_ = data else {
return
}
do {
let jsonObj = try JSONSerialization.jsonObject(with: data_, options: .mutableContainers) as? NSDictionary
guard let parseJSON = jsonObj else {
return
}
self.navigationItem.rightBarButtonItem = self.rightBarButton
let meta = parseJSON["meta"] as? [String:Any]
let status = meta!["status"] as? String
if status == "200" {
isEmployeeModified = true
self.dismiss(animated: true, completion: nil)
} else {
let info = meta!["info"] as? String
let message = meta!["message"] as? String
DispatchQueue.main.async {
self.alertController.singleButtonAlertController(info!, message!, self, self.defaultAction)
}
}
} catch let error as NSError {
print(error)
}
}
task.resume()
I have used similar codes in other parts of the project and everything checks out.

According to this Error, the response from your server is not a valid JSON
Can you use responseString instead of responseJSON like below
Alamofire.request(URL, method: requestMethod, parameters: params).responseString{ response in
print(response)
}

I was able to figure out what was wrong and I'm going to explain this here for future readers. Apparently, I was doing a GET request the wrong way, so when I intend to do a POST request, for some reason, it still sees it as a GET request and that was why I kept getting the response: Error Domain=NSCocoaErrorDomain Code=3840 "No value." UserInfo={NSDebugDescription=No value.}
Below is my refactored code and it works without any hassle:
let dict = [
"phone": phone,
"firstname": firstName,
"lastname": lastName
] as [String : Any]
guard let jsonData = try? JSONSerialization.data(withJSONObject: dict, options: []) else {
return
}
guard let url = URL(string: "\(config.baseURL)employee") else {
return
}
var request = URLRequest(url: url)
request.httpMethod = "POST"
request.addValue("application/json", forHTTPHeaderField: "Content-Type")
request.httpBody = jsonData as Data
request.timeoutInterval = 10
let session = URLSession.shared
session.dataTask(with: request) { (data, response, error) in
if let response = response {
print("JSON Response: \(response)")
}
if error != nil {
DispatchQueue.main.async {
self.navigationItem.rightBarButtonItem = self.rightBarButton
self.alertController.singleButtonAlertController("Error", (error?.localizedDescription)!, self, self.defaultAction)
return
}
}
if let data = data {
do {
let parseJSON = try JSONSerialization.jsonObject(with: data, options: []) as? NSDictionary
let meta = parseJSON!["meta"] as? [String:Any]
let status = meta!["status"] as? String
if status == "200" {
isEmployeeModified = true
self.dismiss(animated: true, completion: nil)
} else {
let info = meta!["info"] as? String
let message = meta!["message"] as? String
DispatchQueue.main.async {
self.alertController.singleButtonAlertController(info!, message!, self, self.defaultAction)
}
}
} catch {
print(error)
}
}
}.resume()

Related

How to get JSON response data from shared class to ViewController?

I'm not using Alamofire, so i want to use JSON post approach in SharedClass and i want to send my api name and all parameters to that function. Finally i want to get the response back. I tried but it's not working. If it's not correct please correct me or if any other options are available please suggest me.
My code in SharedClass
func postRequestFunction(apiName:String , parameters:String ) -> [String:Any] {
var localURL = "hostname/public/index.php/v/***?"
localURL = localURL.replacingOccurrences(of: "***", with: apiName)
var request = URLRequest(url: URL(string: localURL)!)
request.setValue("application/x-www-form-urlencoded", forHTTPHeaderField: "Content-Type")
request.httpMethod = "POST"
print("shared URL : \(request)")
request.httpBody = parameters.data(using: .utf8)
var returnRes:[String:Any] = [:]
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!)
// print("error=\(String(describing: error))")
print("localizedDescription : \(String(describing: error?.localizedDescription))")
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 = \(String(describing: response))")
}
do {
returnRes = try JSONSerialization.jsonObject(with: data, options: []) as! [String : Any]
print(returnRes)
} catch let error as NSError {
print(error)
}
}
task.resume()
return returnRes
}
In my view controller class my code is. Here i'm calling function
func getProjectDetails() {
let response = SharedClass.sharedInstance.postRequestFunction(apiName: "API Name", parameters: parameters)
print(response)
let res = response["Response"] as! [String:Any]
let status = res["status"] as! String
if status == "SUCCESS" {
//I will handle response here
} else {
let message = res["message"] as! String
//Call alert function
SharedClass.sharedInstance.alert(view: self, title: "", message: message)
}
}
Here is my solution:
class APIManager {
private init () {}
static let shared = APIManager()
func postRequestFunction(apiName: String , parameters: String, onCompletion: #escaping (_ success: Bool, _ error: Error?, _ result: [String: Any]?)->()) {
var localURL = "hostname/public/index.php/v/***?"
localURL = localURL.replacingOccurrences(of: "***", with: apiName)
var request = URLRequest(url: URL(string: localURL)!)
request.setValue("application/x-www-form-urlencoded", forHTTPHeaderField: "Content-Type")
request.httpMethod = "POST"
print("shared URL : \(request)")
request.httpBody = parameters.data(using: .utf8)
var returnRes:[String:Any] = [:]
let task = URLSession.shared.dataTask(with: request) { data, response, error in
if let error = error {
onCompletion(false, error, nil)
} else {
guard let data = data else {
onCompletion(false, error, nil)
return
}
if let httpStatus = response as? HTTPURLResponse, httpStatus.statusCode == 200 {
do {
returnRes = try JSONSerialization.jsonObject(with: data, options: []) as! [String : Any]
onCompletion(true, nil, returnRes)
} catch let error as NSError {
onCompletion(false, error, nil)
}
} else {
onCompletion(false, error, nil)
}
}
}
task.resume()
}
}
func getProjectDetails() {
/* Notes:
** onCompletion Block Parameters:
success - This indicates whether the API called successfully or not.
error - This indicates errors from either API calling failed, JSON parsing, or httpStatus is not 200.
result - This indicates the JSON parsed result.
** APIManager:
I have renamed your SharedClass to APIManager for better readibility.
** sharedInstance:
I have renamed sharedInstance to shared for better readibility.
*/
APIManager.shared.postRequestFunction(apiName: "API Name", parameters: "parameters") { (success, error, result) in
if success {
if let res = result?["Response"] as? [String: Any] {
if let status = res["status"] as? String {
if status == "SUCCESS" {
//You can handle response here.
} else {
let message = res["message"] as! String
//Call alert function.
}
}
}
} else {
print(error?.localizedDescription)
}
}
}
You forgot the asynchronous paradigm of Service, You can return your API response in Closure, as like below
func postRequestFunction(apiName:String , parameters:String, returnRes: #escaping ([String: Any]) -> () ) {
var localURL = "hostname/public/index.php/v/***?"
localURL = localURL.replacingOccurrences(of: "***", with: apiName)
var request = URLRequest(url: URL(string: localURL)!)
request.setValue("application/x-www-form-urlencoded", forHTTPHeaderField: "Content-Type")
request.httpMethod = "POST"
print("shared URL : \(request)")
request.httpBody = parameters.data(using: .utf8)
let task = URLSession.shared.dataTask(with: request) { data, response, error in guard let data = data, error == nil else {
// check for fundamental networking 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 = \(String(describing: response))")
}
do {
if let response = try JSONSerialization.jsonObject(with: data, options: []) as? [String : Any] {
returnRes(response)
}
} catch let error as NSError {
print(error)
}
}
task.resume()
}
And use like below
postRequestFunction(apiName: "yourUrl", parameters: "Param") { (response) in
print(response)
}

How to reload new data to UITable when one row data is deleted or updated in swift IOS?

So for I've a UITableView in which I'm showing comments which is fetch from my localhost DB, when a user post comment it's send to localhost and store there and it the same time I reload table and the comment is shown it the time but when a user delete a comment or update a comment then in the DB data is actually deleted or updated but my tableview is not reloading with new data till I close the view and open it again.
following is my code.
This my delete comment code:
#objc func deleteComment(){
ProgressHUD.show("Wait Deleting", interaction: false)
customView.removeFromSuperview()
var commentArray : Dictionary<String, Any> = [:]
commentArray["commentId"] = self.getCommentId
let myUrl = URL(string: "http://127.0.0.1:8000/api/comment/delete");
var request = URLRequest(url:myUrl!)
request.httpMethod = "POST"// Compose a query string
request.addValue("application/json", forHTTPHeaderField: "Content-type")
guard let httpbody = try? JSONSerialization.data(withJSONObject: commentArray, options: []) else { return }
request.httpBody = httpbody
let task = URLSession.shared.dataTask(with: request) { (data: Data?, response: URLResponse?, error: Error?) in
if error != nil
{
print("error=\(error)")
return
}
// print out response object
// print("response = \(response)")
//Let's convert response sent from a server side script to a NSDictionary object:
do {
let json = try JSONSerialization.jsonObject(with: data!, options: .mutableContainers) as? NSDictionary
if let parseJSON = json {
if parseJSON["delete"] != nil{
ProgressHUD.dismiss()
self.alertDeleted()
}else {
if parseJSON["error"] != nil{
ProgressHUD.dismiss()
print(parseJSON["error"] as Any)
}
}
}
} catch {
print(error)
}
}
task.resume()
}
This is delete comment alert.
public func alertDeleted(){
let alertController = UIAlertController(title: "Comment Deleted:", message: "Press Ok to continue.", preferredStyle: .alert)
let confirmAction = UIAlertAction(title: "Ok", style: .default) { (_) in
self.showMatchCommentsApiCall()
}
alertController.addAction(confirmAction)
self.present(alertController, animated: true, completion: nil)
}
This is update comment code.
#objc func updateComment(){
ProgressHUD.show("Wait Upating", interaction: false)
updateCommentView.removeFromSuperview()
var commentArray : Dictionary<String, Any> = [:]
commentArray["commentId"] = self.getCommentId
commentArray["updatedComment"] = textView.text
let myUrl = URL(string: "http://127.0.0.1:8000/api/comment/update");
var request = URLRequest(url:myUrl!)
request.httpMethod = "POST"// Compose a query string
request.addValue("application/json", forHTTPHeaderField: "Content-type")
guard let httpbody = try? JSONSerialization.data(withJSONObject: commentArray, options: []) else { return }
request.httpBody = httpbody
let task = URLSession.shared.dataTask(with: request) { (data: Data?, response: URLResponse?, error: Error?) in
if error != nil
{
print("error=\(error)")
return
}
// print out response object
//print("response = \(response)")
//Let's convert response sent from a server side script to a NSDictionary object:
do {
let json = try JSONSerialization.jsonObject(with: data!, options: .mutableContainers) as? NSDictionary
if let parseJSON = json {
if parseJSON["update"] != nil{
ProgressHUD.dismiss()
self.alertCommentUpdated()
self.showMatchCommentsApiCall()
return
}else {
if parseJSON["error"] != nil{
ProgressHUD.dismiss()
print(parseJSON["error"] as Any)
}
}
}
} catch {
print(error)
}
}
task.resume()
}
My ShowMatchCommentsApiCall() function.
public func showMatchCommentsApiCall(){
ProgressHUD.show("Please Wait", interaction: false)
guard let url = URL(string: "http://127.0.0.1:8000/api/matchComments/\(getMatchId)") else {return}
let task = URLSession.shared.dataTask(with: url) { (data, response, error) in
guard let dataResponse = data,
error == nil else {
print(error?.localizedDescription ?? "Response Error")
return }
do{
//here dataResponse received from a network request
let jsonResponse = try JSONSerialization.jsonObject(with:
dataResponse, options: [])
// print(jsonResponse) //Response result
guard let jsonArray = jsonResponse as? [[String: Any]] else {
return
}
//print(jsonArray)
for comments in jsonArray{
guard let commentID = comments["commentId"] as? Int else { return }
guard let userID = comments["userId"] as? Int else { return }
guard let userName = comments["userName"] as? String else { return }
let userImgUrl = comments["userImg"] as? String
if userImgUrl != nil{
self.commentsUserImgUrl.append(userImgUrl!)
}else {
self.commentsUserImgUrl.append("nil")
}
guard let commentMessage = comments["comment"] as? String else { return }
self.commentId.append(commentID)
self.commmentsUserId.append(userID)
self.commentsUserName.append(userName)
self.comments.append(commentMessage)
}
} catch let parsingError {
print("Error", parsingError)
}
DispatchQueue.main.async {
self.MatchScoreTable.reloadData()
ProgressHUD.dismiss()
}
}
task.resume()
}
STEP 1. :self.commentsArray.remove(at: indexPath.row)
STEP 2. : self.tableView.deleteRows(at:[indexPath],with:UITableViewRowAnimation.automatic)
STEP 3. : self.tableView.reloadData()
After deleting or updating data just call a UITableView method reloadData
Syntax is as follows :
tableView.reloadData()

Using POST request in HTTP method holds the UI?

When I tap on button it will perform a service request operation.Based on the result it will redirect to next view controller.
After loading Next view controller holds or block the UI. How to solve this issue ? I am using RestAPI and GCD first time in swift, so don't know how to solve this.....
This is login button
#IBAction func btnLogin(_ sender: Any)
{
self.api()
}
This is the function what we call.
func api()
{
let myURL = URL(string: "http://www.digi.com/laravel_api_demo/api/demoapipost")
let request = NSMutableURLRequest(url: myURL!)
request.httpMethod = "POST"
let strEmail = tfLgnID.text
let strPwd = tfPwd.text
let postString = ["username":strEmail, "password":strPwd]
//let postString = ["username":"ayush", "password":"abc"]
request.addValue("application/json", forHTTPHeaderField: "Content-Type")
request.addValue("application/json", forHTTPHeaderField: "Accept")
//create the session object
//let session = URLSession.shared
do {
request.httpBody = try JSONSerialization.data(withJSONObject: postString, options: .prettyPrinted) // pass dictionary to nsdata object and set it as request body
print("Successfully passed data to server")
} catch let error {
print(error.localizedDescription)
}
let postTask = URLSession.shared.dataTask(with: request as URLRequest) { (data, response, error) in
guard error == nil else {
return
}
guard let data = data else {
return
}
do {
//create json object from data
if let json = try JSONSerialization.jsonObject(with: data, options: .mutableContainers) as? [String: Any] {
print("POST Method :\(json)")
let dict = json as? [String: Any]
let num = dict!["status"]
print("Status : \(num)")
print("Dict : \(dict)")
print("username : \(dict!["username"])")
print("password : \(dict!["password"])")
if dict!["status"] as! Int == 1
{
print("Successfully Logged In")
DispatchQueue.main.async {
let visitorVC = self.storyboard?.instantiateViewController(withIdentifier: "VisitorVC") as! VisitorVC
self.present(visitorVC, animated: true, completion: nil)
}
print("OK")
}
else
{
print("Not OK")
}
// handle json...
}
} catch let error {
print(error.localizedDescription)
}
}
postTask.resume()
}
Try this method
func api() {
var request = URLRequest(url: URL(string: "")!) // put your url
request.httpMethod = "POST"
let strEmail = tfLgnID.text
let strPwd = tfPwd.text
let postString:String = "user_id=\(strEmail)&user_id=\(strPwd)"
request.httpBody = postString.data(using: .utf8)
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
}
do {
if let jsonResult = try JSONSerialization.jsonObject(with: data, options: JSONSerialization.ReadingOptions.mutableContainers) as? NSDictionary {
print(jsonResult)
let status = jsonResult["status"]! as! NSString
print("status\(status)")
DispatchQueue.main.async(execute: {
// your error Alert
})
}
else {
DispatchQueue.main.async(execute: {
let visitorVC = self.storyboard?.instantiateViewController(withIdentifier: "VisitorVC") as! VisitorVC
self.present(visitorVC, animated: true, completion: nil)
})
}
}
} catch let error as NSError {
print(error.localizedDescription)
}
if let httpStatus = response as? HTTPURLResponse, httpStatus.statusCode != 200 { // check for http errors
print("statusCode should be 200, but is \(httpStatus.statusCode)")
print("response = \(String(describing: response))")
}
let responseString = String(data: data, encoding: .utf8)
print("responseString = \(String(describing: responseString))")
}
task.resume()
}

How to send form data in POST request in Swift 3

I am trying to post form-data using webservice, userName & password, but in response it's showing an error stating "Could not connect to the server.".
Please help me to send form data in the POST request.
let dict:[String:String] = ["userName": userName as! String, "password": password as! String]
do {
let jsonData = try JSONSerialization.data(withJSONObject: dict, options: .prettyPrinted)
let url = URL(string: "(some url)")!
var request = URLRequest(url: url)
request.httpMethod = "POST"
request.setValue("application/x-www-form-urlencoded charset=utf-8", forHTTPHeaderField: "Content-Type")
request.httpBody = jsonData
let task = URLSession.shared.dataTask(with: request) { data, response, error in
if error != nil {
print(error!.localizedDescription)
return
}
do {
let json = try JSONSerialization.jsonObject(with: data!, options: .mutableContainers) as? NSDictionary
if let parseJSON = json {
let resultValue:String = parseJSON["success"] as! String;
print("result: \(resultValue)")
print(parseJSON)
}
} catch let error as NSError {
print(error)
}
}
task.resume()
} catch {
print(error.localizedDescription)
}
I've tried adding values in the request, may be some values are missing in the request formed. Please help!
Thats the POSTMAN response
my calling api class
class ApiService
{
static func getPostString(params:[String:Any]) -> String
{
var data = [String]()
for(key, value) in params
{
data.append(key + "=\(value)")
}
return data.map { String($0) }.joined(separator: "&")
}
static func callPost(url:URL, params:[String:Any], finish: #escaping ((message:String, data:Data?)) -> Void)
{
var request = URLRequest(url: url)
request.httpMethod = "POST"
let postString = self.getPostString(params: params)
request.httpBody = postString.data(using: .utf8)
var result:(message:String, data:Data?) = (message: "Fail", data: nil)
let task = URLSession.shared.dataTask(with: request) { data, response, error in
if(error != nil)
{
result.message = "Fail Error not null : \(error.debugDescription)"
}
else
{
result.message = "Success"
result.data = data
}
finish(result)
}
task.resume()
}
}
and when use it
ApiService.callPost(url: url, params: params, finish: finishPost)
and the finish function
func finishPost (message:String, data:Data?) -> Void
{
do
{
if let jsonData = data
{
let parsedData = try JSONDecoder().decode(Response.self, from: jsonData)
print(parsedData)
}
}
catch
{
print("Parse Error: \(error)")
}
}

post parameter to sever using dictionary swift

I am trying to send data to the server using a dictionary but unfortunately the data is not saving to the database (fields were found to be blank) and I am getting the below response:
Optional(["status": true, "msg": successfull])
And also tried to show UIActivityIndicator to user until he got a response but couldn't find a way.
Code attempted:
let dict = [ "key_one": self.tf1.text!,"key_two":self.tf2.text!]
do {
let jsonData = try NSJSONSerialization.dataWithJSONObject(dict, options: .PrettyPrinted)
// create post request
let url = NSURL(string: "myAPIUrl.php?")!
let request = NSMutableURLRequest(URL: url)
request.HTTPMethod = "POST"
// insert json data to the request
request.setValue("application/json; charset=utf-8", forHTTPHeaderField: "Content-Type")
request.HTTPBody = jsonData
let task = NSURLSession.sharedSession().dataTaskWithRequest(request){ data, response, error in
if error != nil{
print("Error -> \(error)")
return
}
do {
let result = try NSJSONSerialization.JSONObjectWithData(data!, options: []) as? [String:AnyObject]
print("Response -> \(result)")
} catch {
print("Inside Error Section -> \(error)")
}
}
task.resume()
} catch {
print(error)
}
// write this in one fucantion
let Username:NSString = EmailTextField.text! as NSString
let password:NSString = PasswordTextField.text! as NSString
let headers = [
"content-type": "application/json",
"cache-control": "no-cache",
"postman-token": "121b2f04-d2a4-72b7-a93f-98e3383f9fa0"
]
let parameters = [
"username": "\(Username)",
"password": "\(password)"
]
if let postData = (try? JSONSerialization.data(withJSONObject: parameters, options: [])) {
var request = NSMutableURLRequest(url: URL(string: "YOUR_URL_HERE")!,
cachePolicy: .useProtocolCachePolicy,
timeoutInterval: 10.0)
request.httpMethod = "POST"
request.allHTTPHeaderFields = headers
request.httpBody = postData
let session = URLSession.shared
let task = URLSession.shared.dataTask(with: request as URLRequest) {
(data, response, error) -> Void in
if (error != nil) {
print(error)
} else {
DispatchQueue.main.async(execute: {
if let json = (try? JSONSerialization.jsonObject(with: data!, options: [])) as? NSDictionary
{
let success = json["status"] as? Int
let message = json["message"] as? String
// here you check your success code.
if (success == 1)
{
print(message)
let vc = UIActivityViewController(activityItems: [image], applicationActivities: [])
present(vc, animated: true)
}
else
{
// print(message)
}
}
})
}
}
task.resume()
}

Resources