Synchronized a function call - ios

Consider a scenario, I have a function "REFRESH TOKEN", this function is called by different methods simultaneously, let's say the methods are "A", "B", "C".
If method "A" calls "REFRESH TOKEN" firstly then methods "B" and "C" should wait until it finishes.
Does anybody have a sample swift code?
How can I attain this scenario? Appreciate your help!
let serialQueue = DispatchQueue(label: "serialQueue")
var myFlag = false
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
self.refresh(param: 1)
self.refresh(param: 2)
self.refresh(param: 3)
}
func refresh(param: NSInteger) -> Void {
let absolutePath = "MY SAMPLE API"
var headers: [String: String] = Dictionary<String, String>();
headers["Content-Type"] = "application/json"
serialQueue.sync {
print("\nEntered ", param)
Alamofire.request(absolutePath, method: .get, parameters: nil, encoding: JSONEncoding.default, headers: headers).responseString {
response in
switch response.result {
case .success:
print("SUCCESS")
break
case .failure(let error):
print(error)
}
}
}}
Output:
Entered 1
Entered 2
Entered 3
SUCCESS
SUCCESS
SUCCESS
I need an output like this:
Entered 1
SUCCESS
Entered 2
SUCCESS
Entered 3
SUCCESS

You can make use of DispatchGroup.
let dispatchGroup = DispatchGroup()
dispatchGroup.enter()
Method A {
//Refresh Token code here
dispatchGroup.leave()
}
dispatchGroup.wait()
dispatchGroup.enter()
Method B {
//Refresh Token code here
dispatchGroup.leave()
}
dispatchGroup.wait()
dispatchGroup.notify(queue: .main) {
print("Both functions are invoked one after other")
}

The easy and nasty way is to set a flag and check the flag on calling the function and changing flag on returning.
A better way, as far as I found out, is using operation queue.

You should create a dispatchQueue(Serial) and put that code in sync of that queue.
//Create a dispatch Queue
var dispatchQueue:DispatchQueue
func refreshToken() {
dispatchQueue.sync {
//whatever code is there in refreshToken method
}
}

Request chaining is one way. If you find that you have to do this a lot then maybe look into futures and promises. Another way is to use Dispatch Group.
Request Chain example
Alamofire.request(.GET, "http://httpbin.org/get", parameters: ["foo": "bar"]).response { (_, _, data, error) in
if error == nil {
Alamofire.request(.GET, "http://httpbin.org/get2\(data.something)", parameters: ["foo": "bar"]).response { (_, _, something, error) in
fulfill(something)
}
} else {
reject(error)
}
}
Dispatch Group Example:
DispatchQueue.global(qos: .userInitiated).async {
var storedError: NSError?
let downloadGroup = DispatchGroup()
downloadGroup.enter()
Alamofire.request(.GET, "http://httpbin.org/get", parameters: ["foo":
"bar"]).response { (_, _, data, error) in
downloadGroup.leave()
}
downloadGroup.wait()
downloadGroup.enter()
Alamofire.request(.GET, "http://httpbin.org/get", parameters: ["foo":
"bar"]).response { (_, _, data, error) in
downloadGroup.leave()
}
downloadGroup.wait()
downloadGroup.notify(queue: DispatchQueue.main) {
completion?(storedError)
}
}
If you want to look into Futures and Promises Alamofire made a lib
https://github.com/PromiseKit/Alamofire-

Related

Delay task until completed

It is a very common question for people to ask "How do I delay a function or a chunk of code?" but that is not what I need here.
I need my code to wait until a certain task is complete, otherwise my function receives an error that I have no access_token (as the code doesn't wait for fetching the data from the Spotify server).
Here is my code so far, with the attempt to add a DispatchGroup:
func getAccessToken() throws -> Spotify.JSONStandard {
var accessToken: Spotify.JSONStandard!
let group = DispatchGroup() // <- Create group
group.enter() // <- Enter group
Alamofire.request("https://accounts.spotify.com/api/token", method: .post, parameters: spotify.parameters, headers: nil).responseJSON(completionHandler: {
response in
// Check if response is valid
if let newValue = response.result.value as? Spotify.JSONStandard {
accessToken = newValue
}
group.leave() // <- Leave group
})
group.wait() // <- Wait until task is completed
// \/ Delay this code until complete \/
if accessToken != nil {
return accessToken
}
else {
throw SpotifyError.failedToGetAccessToken
}
// /\ /\
}
Without the groups, my code throws SpotifyError.failedToGetAccessToken (the access_token is nil).
However, after adding the groups, my code just hangs and waits forever. How can I delay this code from being completed?
I know getting the token has no issues, as if I remove the return and place a print within the request, I get my expected result.
If you have any questions, please ask
Don't try to make an asynchronous task synchronous
This is a solution with a completion handler and a custom enum for convenience
enum Result {
case success(Spotify.JSONStandard), failure(Error)
}
func getAccessToken(completion: #escaping (Result)->()) {
Alamofire.request("https://accounts.spotify.com/api/token", method: .post, parameters: spotify.parameters, headers: nil).responseJSON(completionHandler: {
response in
// Check if response is valid
if let newValue = response.result.value as? Spotify.JSONStandard {
completion(.success(newValue)
} else {
completion(.failure(SpotifyError.failedToGetAccessToken))
}
})
}
and call it
getAccessToken { result in
switch result {
case .success(let token) : // do something with the token
case .failure(let error) : // do something with the error
}
}

Semaphore to sync request Swift4 stopped forever

I need sync request from web service, so I use sempahore:
class func syncProducts() {
print("syncProducts() 1")
let idsLocal = getProductsIds()
let semaphore = DispatchSemaphore(value: 0)
var idsCloud : [Int] = []
print("Getting cloud ids... 1")
OdooService.getProductsIds { (params: [Int]) in
print("SuccessBlock size ids: \(params.count) 1")
idsCloud = params
semaphore.signal()
}
semaphore.wait()
print("Depois do GetproductsIds: 1")
}
but in this example, the app keep locks forever! The request never ends. This is my function to request data from webserver and returns to success block if is case.
static func getProductsIds(successBlock: #escaping (_ params: [Int]) -> Void) {
// check odoo auth
let dispatch = DispatchGroup()
if( OdooAuth.uid == 0 ) {
print("Odoo offline, tentando reconectar...")
dispatch.enter()
OdooAuth.reconnect(successBlock: { params in
print("Reconectado com sucesso...")
dispatch.leave()
}, failureBlock: { params in
print("Falha no ReAuth")
return
})
}
print("Start request from Odoo...")
let fieldsProducts = ["id"]
let options = [ "fields": fieldsProducts] as [String : Any]
var idsList : [Int] = []
let params = [OdooAuth.db, OdooAuth.uid, OdooAuth.password,"product.template","search_read",[],options] as [Any]
AlamofireXMLRPC.request(OdooAuth.host2, methodName: "execute_kw", parameters: params).responseXMLRPC {
(response: DataResponse<XMLRPCNode>) -> Void in
switch response.result {
case .success( _):
print("Success to get Ids")
let str = String(data: response.data!, encoding: String.Encoding.utf8) as String!
let options = AEXMLOptions()
let xmlDoc = try? AEXMLDocument(xml: (str?.data(using: .utf8))!,options: options)
//print(xmlDoc!.xml)
for child in (xmlDoc?.root["params"]["param"]["value"]["array"]["data"].children)! {
for childValue in child["struct"].children {
let id = childValue["value"]["int"].value!
idsList.append(Int(id)!)
//print("Id: \(id)")
}
}
successBlock(idsList)
break
case .failure(let error):
print("Error to get Ids: \(error.localizedDescription)")
break
} // fim switch
} // fim request
} // fim getProductsIds
I don't know if semaphores is the best way to do this, but I need sync the requests! I tried use DispatchGroup() like in reauth, but not works too.
I would expect that the deadlock is a result of getProductsIds callback being called on main thread, which is blocked by the semaphore. As far as I know, by default Alamofire dispatches the callback on the main thread, which I would expect is the case of AlamofireXMLRPC, since it is a wrapper around Alamofire.
I would strongly recommend to not block main thread during an async operation.
If, however, for any really really good reason you cannot do otherwise, you will need to make sure that the callback won't get dispatched on the main dispatch queue (since that one is blocked waiting for the signal). Alamofire itself has a response overload that allows to specify the DispatchQueue object on which to run the callback. It seems that AlamofireXMLRPC has one too, so I would try to utilize that and change
AlamofireXMLRPC.request(OdooAuth.host2, methodName: "execute_kw", parameters: params)
.responseXMLRPC {
// process result
}
to:
AlamofireXMLRPC.request(OdooAuth.host2, methodName: "execute_kw", parameters: params)
.responseXMLRPC(queue: DispatchQueue.global(qos: .background)) {
// process result
}
I based it on the github source code of AlamofireXMLRPC, but have not worked with it before, so maybe there will be some syntactic errors. But it should point you to right direction. Still, I would recommend you NOT to block the thread (I am repeating myself, but this is really very important point).

Synchronous Alamofire Request with DispatchGroup

I need to wait until Alamofire request finishes getting data. (Error or value). I'm calling Alamofire function inside a for loop in another function so that Alamofire requests should be finished before second for loop called. For example; first loop -> first request -> second loop -> second request...so on. Now It goes first loop -> second loop -> and after all loops finishes requests response is turning.
Request Function:
func like(sender_id: String, completion: #escaping (String?) -> ()){
let group = DispatchGroup()
if let key = api_key{
let headers: HTTPHeaders = [
"X-Auth-Token": key,
"Accept": "application/json"
]
group.enter()
Alamofire.request(baseUrl + likeURL + sender_id, method: .get, parameters: nil, encoding: URLEncoding.default, headers: headers).validate()
.responseJSON { (response) -> Void in
guard response.result.isSuccess else {
print("Error while doing : \(response.result.error)")
completion(nil)
group.leave()
return
}
if let error = response.error{
completion(nil)
group.leave()
print("Error Occured with Request: \(error)")
}
if let jsonData = response.data{
let json = JSON(data: jsonData)
print(json)
group.leave()
if let matched = json["match"].bool{
completion(matched.description)
print("Liked!: \(matched)")
if(matched){
}
}else{
group.leave()
"There is an error with JSON"
}
}}
}
}
Where I call:
func like_all(completion: #escaping() -> ()){
for user in SharedUsers.sharedUser.users{
if let id = user.id{
Network.sharedInstance.like(sender_id: id) { result in
print(result)
}
}
else{
continue
}
}
completion()
}
You are using dispatch group, obviously with the intent on waiting for the group at the end of the function. But you're not waiting for it, so you're not getting the synchronous behavior you were looking for.
But that's good, because if you wait for that group (or semaphore, the other pattern to achieve this behavior) on the main thread, not only will you be blocking the main thread (which results in horrible UX and risk having your app killed by watchdog process), you're going to deadlock because responseJSON uses the main queue for it's completion handler. So before you add the wait() call on your dispatch group/semaphore, make sure you dispatch this whole for loop asynchronously to some background thread. That avoids blocking the main thread and eliminates the deadlock risk.
But this whole pattern is fundamentally flawed, as you really shouldn't use dispatch groups or semaphores to make it synchronous at all. That raises a few questions:
The first question is why you want to make this synchronous. Network requests have inherent latency, so you performing a sequence of them will be very slow. Only do this sequence of requests if you absolutely have to (e.g. each request cannot be formed because it needs something from the response of the prior request). But that doesn't appear to be the case here. So why make this process unnecessary so.
But let's assume for a second that you absolutely have to perform these sequentially (not true here, from what I can tell, but let's tease this out). Then there are two patterns for performing a series of requests consecutively rather than concurrently:
You can either lose this for loop entirely, and simply have a routine that sends the n-th request and sends request n+1 in its completion handler. That completely eliminates the need for dispatch groups/semaphores to block a thread.
Or you can wrap this in operation (e.g. https://stackoverflow.com/a/27022598/1271826) and use operation queue.
I solve it by calling like function with index + 1 everytime Alamofire returns value. I also call function in completion part of fetch request.
Here is the code:
#objc func action(_ sender: LGButton) {
sender.titleString = "Started to Like :)"
Network.sharedInstance.get_rec(completion: { (result) in
if(result != nil)
{
Network.sharedInstance.like(sender: 0, completion: { (result) in
//print(result)
})
}
})
}
Like Function:
func like(sender: Int, completion: #escaping (String?) -> ()){
if let key = api_key{
let headers: HTTPHeaders = [
"X-Auth-Token": key,
"Accept": "application/json"
]
print(sender)
print(SharedUsers.sharedUser.users.count)
if(sender < SharedUsers.sharedUser.users.count){
if let user_id = SharedUsers.sharedUser.users[sender].id{
Alamofire.request(baseUrl + likeURL + user_id, method: .get, parameters: nil, encoding: URLEncoding.default, headers: headers).validate()
.responseJSON { (response) -> Void in
guard response.result.isSuccess else {
print("Error while doing : \(response.result.error)")
completion(nil)
return
}
if let error = response.error{
completion(nil)
print("Error Occured with Request: \(error)")
}
if let jsonData = response.data{
let json = JSON(data: jsonData)
if let matched = json["match"].bool{
completion(matched.description)
print("Liked!: \(matched)")
if(sender <= SharedUsers.sharedUser.users.count){
self.like(sender: sender + 1, completion: {result in
//print(result)
})
}else{
return
}
if(matched){
}
}else{
"There is an error with JSON"
}}}
}else{return}
}}}

wait for response Alamofire swift

I need to wait for response.response?.allHeaderFields data before executing function. I've searched the net and didn't quite get how to add "completion handler" to alamofire request. Or if there are any other ways to make the function wait.
#IBAction func comfirmation(sender: UIButton) {
if CodeTextField.text != "" {
print("in comfirmation function")
let comfirmationRequestData = [
"phone" : "\(appDelegate.savedNumber)",
"code" : "\(CodeTextField.text!)"
]
Alamofire.request(.POST,
"http://192.168.214.241:4000/login",
parameters: comfirmationRequestData,
encoding: .JSON).responseJSON {
response in
switch response.result {
case .Success:
let jsonDecrypted = JSON(response.result.value!)
print(jsonDecrypted)
let headerFile = response.response?.allHeaderFields as? [String:String]
print(headerFile)
case .Failure(let error):
print(error)
}
}
print("in comfirmation function. success")
appDelegate.defaults.setValue(appDelegate.savedNumber, forKey: "phoneNumber")
} else {
print("in comfirmation function. failed")
}
}
Use Alamofire like this
func postRequest( urlSuffix : String, params:[String : AnyObject]?, filterParams : [String]?, success: (response: AnyObject!) -> Void, failure: (error: NSError?) -> Void)
{
Alamofire.request(.POST, webServicesURLPrefix + urlSuffix, parameters: params, encoding: .JSON, headers: self.headers)
request?.responseJSON { response in
switch response.result
{
case .Success:
success(response: response.result.value)
case .Failure(let error):
failure(error: error)
}
}
}
Call the method from anywhere as
self.postRequest("do-registration.php", params: params, filterParams: nil, success: { (response) -> Void in
self.afterResponse(response)
}) { (error) -> Void in
failure(error: error)
}
OR you can write a saperate method which you will have to call after the completion.
func afterResponse(responseData : AnyObject)
{
print("Done")
print(responseData)
}
You can cause the operation to be synchronous, but in order to do that you are going to have to use a semaphore for that you set up prior to the Alamofire request, and that you then release within the completion handler. You will wait on the semaphore right after you initiate Alamo fire.
There is a library Alamofire-Synchronous which works using semaphore.
Sample:
//json
let response = Alamofire.request(.GET, "https://httpbin.org/get", parameters: ["foo": "bar"]).responseJSON()
if let json = response.result.value {
print(json)
}

Chain multiple Alamofire requests

I'm looking for a good pattern with which I can chain multiple HTTP requests. I want to use Swift, and preferrably Alamofire.
Say, for example, I want to do the following:
Make a PUT request
Make a GET request
Reload table with data
It seems that the concept of promises may be a good fit for this. PromiseKit could be a good option if I could do something like this:
NSURLConnection.promise(
Alamofire.request(
Router.Put(url: "http://httbin.org/put")
)
).then { (request, response, data, error) in
Alamofire.request(
Router.Get(url: "http://httbin.org/get")
)
}.then { (request, response, data, error) in
// Process data
}.then { () -> () in
// Reload table
}
but that's not possible or at least I'm not aware of it.
How can I achieve this functionality without nesting multiple methods?
I'm new to iOS so maybe there's something more fundamental that I'm missing. What I've done in other frameworks such as Android is to perform these operations in a background process and make the requests synchronous. But Alamofire is inherently asynchronous, so that pattern is not an option.
Wrapping other asynchronous stuff in promises works like this:
func myThingy() -> Promise<AnyObject> {
return Promise{ fulfill, reject in
Alamofire.request(.GET, "http://httpbin.org/get", parameters: ["foo": "bar"]).response { (_, _, data, error) in
if error == nil {
fulfill(data)
} else {
reject(error)
}
}
}
}
Edit: Nowadays, use: https://github.com/PromiseKit/Alamofire-
I wrote a class which handles a chain of request one by one.
I created a class RequestChain wich takes Alamofire.Request as parameter
class RequestChain {
typealias CompletionHandler = (success:Bool, errorResult:ErrorResult?) -> Void
struct ErrorResult {
let request:Request?
let error:ErrorType?
}
private var requests:[Request] = []
init(requests:[Request]) {
self.requests = requests
}
func start(completionHandler:CompletionHandler) {
if let request = requests.first {
request.response(completionHandler: { (_, _, _, error) in
if error != nil {
completionHandler(success: false, errorResult: ErrorResult(request: request, error: error))
return
}
self.requests.removeFirst()
self.start(completionHandler)
})
request.resume()
}else {
completionHandler(success: true, errorResult: nil)
return
}
}
}
And I use it like this
let r1 = Alamofire.request(Router.Countries).responseArray(keyPath: "endpoints") { (response: Response<[CountryModel],NSError>) in
print("1")
}
let r2 = Alamofire.request(Router.Countries).responseArray(keyPath: "endpoints") { (response: Response<[CountryModel],NSError>) in
print("2")
}
let r3 = Alamofire.request(Router.Countries).responseArray(keyPath: "endpoints") { (response: Response<[CountryModel],NSError>) in
print("3")
}
let chain = RequestChain(requests: [r1,r2,r3])
chain.start { (success, errorResult) in
if success {
print("all have been success")
}else {
print("failed with error \(errorResult?.error) for request \(errorResult?.request)")
}
}
Importent is that you are telling the Manager to not execute the request immediately
let manager = Manager.sharedInstance
manager.startRequestsImmediately = false
Hope it will help someone else
Swift 3.0 Update
class RequestChain {
typealias CompletionHandler = (_ success:Bool, _ errorResult:ErrorResult?) -> Void
struct ErrorResult {
let request:DataRequest?
let error:Error?
}
fileprivate var requests:[DataRequest] = []
init(requests:[DataRequest]) {
self.requests = requests
}
func start(_ completionHandler:#escaping CompletionHandler) {
if let request = requests.first {
request.response(completionHandler: { (response:DefaultDataResponse) in
if let error = response.error {
completionHandler(false, ErrorResult(request: request, error: error))
return
}
self.requests.removeFirst()
self.start(completionHandler)
})
request.resume()
}else {
completionHandler(true, nil)
return
}
}
}
Usage Example Swift 3
/// set Alamofire default manager to start request immediatly to false
SessionManager.default.startRequestsImmediately = false
let firstRequest = Alamofire.request("https://httpbin.org/get")
let secondRequest = Alamofire.request("https://httpbin.org/get")
let chain = RequestChain(requests: [firstRequest, secondRequest])
chain.start { (done, error) in
}
You have multiple options.
Option 1 - Nesting Calls
func runTieredRequests() {
let putRequest = Alamofire.request(.PUT, "http://httpbin.org/put")
putRequest.response { putRequest, putResponse, putData, putError in
let getRequest = Alamofire.request(.GET, "http://httpbin.org/get")
getRequest.response { getRequest, getResponse, getData, getError in
// Process data
// Reload table
}
}
}
This is definitely the approach I would recommend. Nesting one call into another is very simple and is pretty easy to follow. It also keeps things simple.
Option 2 - Splitting into Multiple Methods
func runPutRequest() {
let putRequest = Alamofire.request(.PUT, "http://httpbin.org/put")
putRequest.response { [weak self] putRequest, putResponse, putData, putError in
if let strongSelf = self {
// Probably store some data
strongSelf.runGetRequest()
}
}
}
func runGetRequest() {
let getRequest = Alamofire.request(.GET, "http://httpbin.org/get")
getRequest.response { [weak self] getRequest, getResponse, getData, getError in
if let strongSelf = self {
// Probably store more data
strongSelf.processResponse()
}
}
}
func processResponse() {
// Process that data
}
func reloadData() {
// Reload that data
}
This option is less dense and splits things up into smaller chunks. Depending on your needs and the complexity of your response parsing, this may be a more readable approach.
Option 3 - PromiseKit and Alamofire
Alamofire can handle this pretty easily without having to pull in PromiseKit. If you really want to go this route, you can use the approach provided by #mxcl.
Here is another way to do this (Swift 3, Alamofire 4.x) using a DispatchGroup
import Alamofire
struct SequentialRequest {
static func fetchData() {
let authRequestGroup = DispatchGroup()
let requestGroup = DispatchGroup()
var results = [String: String]()
//First request - this would be the authentication request
authRequestGroup.enter()
Alamofire.request("http://httpbin.org/get").responseData { response in
print("DEBUG: FIRST Request")
results["FIRST"] = response.result.description
if response.result.isSuccess { //Authentication successful, you may use your own tests to confirm that authentication was successful
authRequestGroup.enter() //request for data behind authentication
Alamofire.request("http://httpbin.org/get").responseData { response in
print("DEBUG: SECOND Request")
results["SECOND"] = response.result.description
authRequestGroup.leave()
}
authRequestGroup.enter() //request for data behind authentication
Alamofire.request("http://httpbin.org/get").responseData { response in
print("DEBUG: THIRD Request")
results["THIRD"] = response.result.description
authRequestGroup.leave()
}
}
authRequestGroup.leave()
}
//This only gets executed once all the requests in the authRequestGroup are done (i.e. FIRST, SECOND AND THIRD requests)
authRequestGroup.notify(queue: DispatchQueue.main, execute: {
// Here you can perform additional request that depends on data fetched from the FIRST, SECOND or THIRD requests
requestGroup.enter()
Alamofire.request("http://httpbin.org/get").responseData { response in
print("DEBUG: FOURTH Request")
results["FOURTH"] = response.result.description
requestGroup.leave()
}
//Note: Any code placed here will be executed before the FORTH request completes! To execute code after the FOURTH request, we need the request requestGroup.notify like below
print("This gets executed before the FOURTH request completes")
//This only gets executed once all the requests in the requestGroup are done (i.e. FORTH request)
requestGroup.notify(queue: DispatchQueue.main, execute: {
//Here, you can update the UI, HUD and turn off the network activity indicator
for (request, result) in results {
print("\(request): \(result)")
}
print("DEBUG: all Done")
})
})
}
}
Details
Alamofire 4.7.2
PromiseKit 6.3.4
Xcode 9.4.1
Swift 4.1
Full Sample
NetworkService
import Foundation
import Alamofire
import PromiseKit
class NetworkService {
static fileprivate let queue = DispatchQueue(label: "requests.queue", qos: .utility)
fileprivate class func make(request: DataRequest) -> Promise <(json: [String: Any]?, error: Error?)> {
return Promise <(json: [String: Any]?, error: Error?)> { seal in
request.responseJSON(queue: queue) { response in
// print(response.request ?? "nil") // original URL request
// print(response.response ?? "nil") // HTTP URL response
// print(response.data ?? "nil") // server data
//print(response.result ?? "nil") // result of response serialization
switch response.result {
case .failure(let error):
DispatchQueue.main.async {
seal.fulfill((nil, error))
}
case .success(let data):
DispatchQueue.main.async {
seal.fulfill(((data as? [String: Any]) ?? [:], nil))
}
}
}
}
}
class func searchRequest(term: String) -> Promise<(json: [String: Any]?, error: Error?)>{
let request = Alamofire.request("https://itunes.apple.com/search?term=\(term.replacingOccurrences(of: " ", with: "+"))")
return make(request: request)
}
}
Main func
func run() {
_ = firstly {
return Promise<Void> { seal in
DispatchQueue.global(qos: .background).asyncAfter(deadline: DispatchTime.now() + .seconds(2)) {
print("1 task finished")
DispatchQueue.main.async {
seal.fulfill(Void())
}
}
}
}.then {
return NetworkService.searchRequest(term: "John").then { json, error -> Promise<Void> in
print("2 task finished")
//print(error ?? "nil")
//print(json ?? "nil")
return Promise { $0.fulfill(Void())}
}
}.then {_ -> Promise<Bool> in
print("Update UI")
return Promise { $0.fulfill(true)}
}.then { previousResult -> Promise<Void> in
print("previous result: \(previousResult)")
return Promise { $0.fulfill(Void())}
}
}
Result
You can use the when method in PromiseKit to attach/append as many calls you want.
Here's an example from PromiseKit docs:
firstly {
when(fulfilled: operation1(), operation2())
}.done { result1, result2 in
//…
}
It worked perfectly for me and it's a much cleaner solution.
Call itself infinitely and DEFINE END CONDITION.
urlring for API link and Dictionary for json
WE may construct the queue model or delegate
func getData(urlring : String , para : Dictionary<String, String>) {
if intCount > 0 {
Alamofire.request( urlring,method: .post, parameters: para , encoding: JSONEncoding.default, headers: nil) .validate()
.downloadProgress {_ in
}
.responseSwiftyJSON {
dataResponse in
switch dataResponse.result {
case .success(let json):
print(json)
let loginStatus : String = json["login_status"].stringValue
print(loginStatus)
if loginStatus == "Y" {
print("go this")
print("login success : int \(self.intCount)")
self.intCount-=1
self.getData(urlring: urlring , para : para)
}
case .failure(let err) :
print(err.localizedDescription)
}
}
}else{
//end condition workout
}
}

Resources