How to call Main Thread after an asynchronous request - ios

When I make the following network request the print statement appears to fire before the async. request has completed. I'm trying to call the main thread only after the async request is complete.
func getRating (articleID: String) {
let endPointURL = "http://www.smarttapp.com/DesktopModules/DnnSharp/DnnApiEndpoint/Api.ashx?method=GetRating"
let encodedarticleIDURL = endPointURL.addingPercentEncoding(withAllowedCharacters: CharacterSet.urlQueryAllowed)!
let myURL = URL(string: encodedarticleIDURL)
Alamofire.request(
myURL!,
parameters: ["articleID": articleID]
)
.responseData { response in
guard response.result.isSuccess else {
return
}
if let data = response.data, let myDataString = String(data: data, encoding: .utf8) {
print("MyDataString is: \(myDataString)")
let newRating = Double(myDataString)!
self.post.rating = newRating
print(newRating)
}
}
DispatchQueue.main.async {
print("Final value \(self.post.rating)")
self.networkingState = .finishedSearching
self.tableView.reloadData()
}
}

You need to do the main thread inside your Alamofire response completion block and it should work
Alamofire.request(
myURL!,
parameters: ["articleID": articleID]
)
.responseData { response in
guard response.result.isSuccess else {
return
}
if let data = response.data, let myDataString = String(data: data, encoding: .utf8) {
print("MyDataString is: \(myDataString)")
let newRating = Double(myDataString)!
self.post.rating = newRating
print(newRating)
}
DispatchQueue.main.async {
print("Final value \(self.post.rating)")
self.networkingState = .finishedSearching
self.tableView.reloadData()
}
}

Related

dataTask of URLSession not running

I'm trying to get results from an API, and I'm having trouble running the request itself.
Here is the code I currently have:
let url = URL(string: "https://httpbin.org/get")!
let task = URLSession.shared.dataTask(with: url) { (data, response, error) in
if let error = error {
print("error: \(error)")
} else {
if let response = response as? HTTPURLResponse {
print("statusCode: \(response.statusCode)")
}
if let data = data, let dataString = String(data: data, encoding: .utf8) {
print("data: \(dataString)")
}
}
}
task.resume()
However, it doesn't seem to run anything inside the code block in dataTask.
Thanks for your help :)
Your code works well. It seems like you're just calling the function incorrectly...try it this way:
1:
func request() {
let url = URL(string: "https://httpbin.org/get")!
let task = URLSession.shared.dataTask(with: url) { (data, response, error) in
if let error = error {
print("error: \(error)")
} else {
if let response = response as? HTTPURLResponse {
print("statusCode: \(response.statusCode)")
}
if let data = data, let dataString = String(data: data, encoding: .utf8) {
print("data: \(dataString)")
}
}
}
task.resume()
}
2:
override func viewDidLoad() {
super.viewDidLoad()
request()
}

ios - How to wait api response using Alamofire

I want to ask about Semaphore in Alamofire.
I want the app wait for data from the server return success and continue to execute the code after (synchronous type). I use semaphore, but when the api function is called, the app is suspended...
This code is call data from server:
func getAllModels() -> [String] {
var _modelList:[String] = []
let url = BASE_URL + "getAllProductAndModelv2"
let semaphore = DispatchSemaphore(value: 0)
Alamofire.request(url, method:.get, parameters: [:], encoding: JSONEncoding.default).responseJSON { response in
let data = NSData(contentsOf: URL(string: url)!)
do {
if let data = data, let json = try JSONSerialization.jsonObject(with: data as Data) as? [String: Any], let models = json["models"] as? [[String:Any]] {
for model in models {
if let name = model["name"] as? String {
_modelList.append(name)
}
}
}
}catch {
print("error")
}
semaphore.signal()
}
semaphore.wait()
return _modelList
}
And this code is going to get the result:
let api = RestApiManager()
var result:[String] = api.getAllModels()
print(result)
How to relsove this issuse?
Thank you
Use completion
func getAllModels( completion: #escaping ([String] ,Bool) -> Void) {
var modelList:[String] = []
let url = BASE_URL + "getAllProductAndModelv2"
Alamofire.request(url, method:.get, parameters: [:], encoding: JSONEncoding.default).responseJSON { response in
let data = NSData(contentsOf: URL(string: url)!)
do {
if let data = data, let json = try JSONSerialization.jsonObject(with: data as Data) as? [String: Any], let models = json["models"] as? [[String:Any]] {
for model in models {
if let name = model["name"] as? String {
modelList.append(name)
}
}
completion(modelList,true)
}
}catch {
print("error")
completion([],false)
}
}
}
Then call it
self.getAllModels { (data, success) in
if(success)
{
// use data
}
}

Swift - How to send POST request with "x-www-form-urlencoded" content-type

I searched a lot and there's no clear instruction for sending POST request with "x-www-form-urlencoded" content-type.
i want to know how to do that and if you know how to do it with Alamofire it would be even better.
any help will be appreciated.
Hope you are searching for this one or give us more explanation in code so we get it easily:
let headers = [
"Content-Type": "application/x-www-form-urlencoded"
]
let parameters = [
]
Alamofire.request("urlString", method: .post, parameters: parameters, encoding: URLEncoding.httpBody, headers: headers).responseJSON { (response:DataResponse<Any>) in
switch(response.result) {
case.success(let data):
print("success",data)
case.failure(let error):
print("Not Success",error)
self.view.makeToast(message: "Server Error!!")
}
}
I used below code in swift 4.2
guard let url = URL(string: "http://192.168.88.129:81/authenticate") else {
return
}
let user1 = username.text!
let pass = passwordfield.text!
print(user1)
print(pass)
let data : Data = "username=\(user1)&password=\(pass)&grant_type=password".data(using: .utf8)!
var request : URLRequest = URLRequest(url: url)
request.httpMethod = "POST"
request.setValue("application/x-www-form-urlencoded", forHTTPHeaderField:"Content-Type");
request.setValue(NSLocalizedString("lang", comment: ""), forHTTPHeaderField:"Accept-Language");
request.httpBody = data
print("one called")
let config = URLSessionConfiguration.default
let session = URLSession(configuration: config)
// vs let session = URLSession.shared
// make the request
let task = session.dataTask(with: request, completionHandler: {
(data, response, error) in
if let error = error
{
print(error)
}
else if let response = response {
print("her in resposne")
}else if let data = data
{
print("here in data")
print(data)
}
DispatchQueue.main.async { // Correct
guard let responseData = data else {
print("Error: did not receive data")
return
}
let decoder = JSONDecoder()
print(String(data: responseData, encoding: .utf8))
do {
// let todo = try decoder.decode(T.self, from: responseData)
// NSAssertionHandler(.success(todo))
} catch {
print("error trying to convert data to JSON")
//print(error)
// NSAssertionHandler(.failure(error))
}
}
})
task.resume()
}
Try this following method using Alamofire
Alamofire.request("yourSide", method: .post, parameters: parameters, encoding: URLEncoding.default)
If it doesn't work, which is unlikely, use this following code
Alamofire.request("yourSide", method: .post, parameters: parameters, encoding: URLEncoding.httpBody)

AFNetworking pass data with "x-www-form-urlencoded" type

In post man if I pass the data with x-www-form-urlencoded it will give me success response in it, but same thing I try with afnetworking then it does not work for me.
I know this question has already answer but some were very old and method which is used in was deprecated and some I tried but not worked for me
My code is as below
static func calledApi(withApiName strName:String,withParameter dictData:NSDictionary,withSuccessBlock objSuccess:successBlock,withFailureBlock objFailure:failureBlock){
strBaseUrl = strBaseUrl.stringByAppendingString(strName)
let manager = AFHTTPSessionManager(sessionConfiguration: NSURLSessionConfiguration.defaultSessionConfiguration())
manager.requestSerializer.setValue("application/x-www-form-urlencoded", forHTTPHeaderField: "Content-Type")
// manager.requestSerializer.setQueryStringSerializationWithBlock { (request, id,error) -> String in
// let jsonData = try! NSJSONSerialization.dataWithJSONObject(dictData, options: .PrettyPrinted)
// let myString = String(data: jsonData, encoding: NSUTF8StringEncoding)
// return myString!
// }
// manager.requestSerializer = AFHTTPRequestSerializer()
manager.responseSerializer = AFHTTPResponseSerializer()
manager.POST(strBaseUrl, parameters: dictData, progress: { (progress) in
}, success: { (session, responceObj) in
let datastring : String = String(data: (responceObj as! NSData), encoding: NSUTF8StringEncoding)!
print(datastring)
var dictData = NSDictionary()
do {
dictData = try NSJSONSerialization.JSONObjectWithData((responceObj as! NSData), options: []) as! [String:AnyObject]
} catch let error as NSError {
print(error)
return
}
if Int(dictData.valueForKey("code") as! String) == 1
{
objSuccess(dictData)
}
else
{
objFailure(nil, dictData.valueForKey("message") as! String)
}
}) { (session, error) in
print(error)
objFailure(error,nil)
}
}

Why NSOperation starts before completion previous operation?

I'm trying the next:
I get response from Alamofire, fill an array
print this array
for this I did:
var queue = NSOperationQueue()
let firstOperation = NSBlockOperation(block: {
let getMyProfileURL = "\(self.property.host)\(self.property.getMyProfile)"
Alamofire.request(.POST, getMyProfileURL, parameters: self.userParameters.profileParameteres, encoding: .JSON).responseJSON { response in
do {
let json = JSON(data: response.data!)
print(json)
if json["user"].count > 0 {
self.profileDetails.append(ProfileDetailsModel(json: json["user"]))
}
}
}
})
firstOperation.completionBlock = {
print("firstOperation completed")
}
queue.addOperation(firstOperation)
let secondOperation = NSBlockOperation(block: {
print(self.profileDetails)
})
secondOperation.addDependency(firstOperation.completionBlock)
secondOperation.completionBlock = {
print(self.profileDetails)
}
queue.addOperation(secondOperation)
So, in the theory, at first it needs to fill my array, complete this task(block) and just later print those array. But I get:
firstOperation completed
[] -> self.profileDetails from the secondOperation
[] -> self.profileDetails from the secondOperation completion block
and just here I get my JSON from the Alamofire 'do' block
So, what I did wrong? And how can I fix it that it will work as I want?
Don't add the second operation until after the first operation completes (e.g. at the end of the first operations block).
First, you have to understand that Alamofire request is always performed in a separate thread.
So your firstOperation is useless. You do not need it because Alamofire is already asynchronous.
var queue = NSOperationQueue()
let secondOperation = NSBlockOperation(block: {
print(self.profileDetails)
})
secondOperation.completionBlock = {
print(self.profileDetails)
}
let getMyProfileURL = "\(self.property.host)\(self.property.getMyProfile)"
Alamofire.request(.POST, getMyProfileURL, parameters: self.userParameters.profileParameteres, encoding: .JSON).responseJSON { response in
do {
let json = JSON(data: response.data!)
print(json)
if json["user"].count > 0 {
self.profileDetails.append(ProfileDetailsModel(json: json["user"]))
}
}
print("Alamofire.request completed") // instead of: print("firstOperation completed")
queue.addOperation(secondOperation)
}

Resources