1

Hi developers im having some issue or misplaced tasks

so i had to develop a framework with some functions

this is my main FUNCTION where the issue began    

func saveDataDevice(idPos: String, macAddress: String) {
        // this first function obtains the MAIN token for further tasks == 'tokenForTransaction'
        let value = FirstInitDevice.tokentransaccional(username: idPos)

//now i'd 2 seconds timer after tokentransaccional is launched 
        DispatchQueue.main.asyncAfter(deadline: .now() + 2.0, execute: {

            //after obtain tokenForTransaction i can do any WS, deviceInitWsCall gets call now it returns 'PosId' 
//after finish the task so i'd save it for further fuctions 
           let value2 = FirstInitDevice.deviceInitWsCall(serialNumber: idPos)
            let posidd = value2.PosId
            let convert = String(posidd)
            UserDefaults.standard.set(convert, forKey: "PosId")
            
            //now i can do the third function using PosId parameter and obtain  'rsa'
            //this is where the trouble shows for the first time, because the application hasn't finish the past task
//FirstInitDevice.deviceInitWsCall is not done yet that's why my if == "" just in case ill show the error immediately
        let value3 = FirstInitDevice.getKeyWS(posId: value2.PosId)
            LoginSingleton.shared.pos_id = value2.PosId
            
            if value3.rsa == "" {
                let alert = UIAlertController(title: "alert", message: "Cannot init KEYS", preferredStyle: UIAlertController.Style.alert)
                       let action = UIAlertAction(title: "OK", style: UIAlertAction.Style.destructive, handler: nil)
                       alert.addAction(action)
                self.present(alert, animated: true, completion: nil)
            }else {
// if not continue
//decrypt rsa data 
            let rsaData = RSA().getRSAData(publicKeyHex: value3.rsa)
                   
                 
                   keysSingleton.shared.tk = rsaData.tk
        
                //func 4 runs after decrypt is done BUT is not, because third function is not over yet 
            let value4 = FirstInitDevice.callInitDukptKeys(pos_id: value2.PosId, rsa: rsaData.rsa, check_value: rsaData.checkValue, crc32: rsaData.crc32)


            //same IF just in case == ""
            if value4.ksnString == ""{
                 let alert = UIAlertController(title: "Alert", message: "Cannot init KEYS", preferredStyle: UIAlertController.Style.alert)
                       let action = UIAlertAction(title: "OK", style: UIAlertAction.Style.destructive, handler: nil)
                       alert.addAction(action)
                self.present(alert, animated: true, completion: nil)
            } else{
                keysSingleton.shared.ksn = value4.ksnString
                keysSingleton.shared.new_key = value4.newKey
                keysSingleton.shared.tk = value4.ksnString
                self.doTransaction()
            }
            }
        })
        

        
    }

as you can see one functions leads to another and so and so, it doesn't work without getting the previous parameter for some reason the applications saves the LAST obtained parameter INSTED the current one, this apply to any other function in the library i have tried

1.- increasing the timer for DispatchQueue.main.asyncAfter(deadline: .now() + 8.0, execute: {

2.- set for every function deadline 8s

3.- set DispatchGroup() .enter .leave to every function

but it didn't work, so the question leads to How can i handle URLSession.shared.dataTask after they finish properly so the response value doesn't gets the past-value

*NOTE: I can't do urlsessiondelegate with conection finishSucessfully i had to work with the library response *

this are the functions on my library

FIRST FUNCTION tokentransaccional

public static func tokentransaccional(username: String){
    let baseUrl = "http://bla bla"

     let headers = [
         "Authorization": "Basic bla bla"
     ]
        let url = URL(string: "bla bla")!
        var request = URLRequest(url: url)
        request.allHTTPHeaderFields = headers
        request.httpMethod = "POST"
        request.timeoutInterval = 60
        request.setValue("application/x-www-form-urlencoded", forHTTPHeaderField: "Content-Type")
        request.setValue("application/json", forHTTPHeaderField: "Accept")
        let password = username+"bla bla"
        let postString = "bla bla"
        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=\(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)")
         }

             do {
                 if let convertedJsonIntoDict = try JSONSerialization.jsonObject(with: data, options: []) as? NSDictionary {

                     let responseError = convertedJsonIntoDict["error"] as? String
                     let errorDescription = convertedJsonIntoDict["error_description"] as? String
                     
                     
                     if responseError?.count == nil {

                         let tokenAcceso = convertedJsonIntoDict["access_token"] as? String
                         LoginSingleton.shared.tokenForTransaction = tokenAcceso ?? ""
                         UserDefaults.standard.set(tokenAcceso, forKey: "AccessTokenLogin")
                     } else {
                         print("error")
                     }
                 }
             }
         catch let error as NSError {
             print("catch let error")
             print(error.localizedDescription)
         }

     }
     task.resume()

     }

second function deviceInitWsCall

public static func deviceInitWsCall(serialNumber: String) -> (PosId: Int, transaction_profile: String) {
        let token = UserDefaults.standard.string(forKey: "AccessTokenLogin") ?? ""
            let headers = [
                "Authorization": "bla bla"
            ]
            let baseUrl = "bla bla"
            let portBPC = "bla bla"
            let deviceInitWsPoint = "bla bla"
        
            let Url = String(format: "bla bla")
             let serviceUrl = URL(string: Url)
            let parameterDictionary = ["bla bla": serialNumber]
            var request = URLRequest(url: serviceUrl!)
            request.httpMethod = "POST"
            request.allHTTPHeaderFields = headers
            request.setValue("application/json; charset=utf-8", forHTTPHeaderField: "Content-Type")
            request.setValue("application/json; charset=utf-8", forHTTPHeaderField: "Accept")
            request.setValue("Bearer \(token)", forHTTPHeaderField: "Authorization")
        
            let httpBody = try? JSONSerialization.data(withJSONObject: parameterDictionary, options: [])
            request.httpBody = httpBody
            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)")
                }
                
                do {
                    if let convertedJsonIntoDict = try JSONSerialization.jsonObject(with: data, options: []) as? NSDictionary {
                        print(convertedJsonIntoDict)
                        let response = convertedJsonIntoDict
                        let status = response["status"] as? Bool
                        if status == true {
                        UserDefaults.standard.set(response, forKey: "deviceInitDictionary")
                       
                         let mainResponse = response["dataResponse"] as! NSDictionary
                         let getPosId = mainResponse["posId"] as! Int
                            UserDefaults.standard.set(getPosId, forKey: "getPosId")
                         let getQps = mainResponse["qps"] as! Bool
                         let getTransactionProfile = mainResponse["transactionProfile"] as! String
                            UserDefaults.standard.set(getTransactionProfile, forKey: "getTransactionProfile")
                         
                         let dataContact = mainResponse["contact"] as! NSDictionary
                         let indicatorPartialCancellation = mainResponse["partialCancellation"] as? Bool
                         LoginSingleton.shared.qps = getQps
                            UserDefaults.standard.set(getQps, forKey: "getQps")

                         LoginSingleton.getInstance().pos_id = getPosId
                         dataPresentReatailPresent.shared.posId = getPosId
                         LoginSingleton.getInstance().qps = getQps
                         LoginSingleton.getInstance().transaction_profile = getTransactionProfile
                         LoginSingleton.getInstance().partialCancellation = indicatorPartialCancellation ?? false


                        }
                        else{
                            print("error")
                        }


                    }
                } catch let error as NSError {
                    print("catch let error")
                    print(error.localizedDescription)
                }
                }.resume()
        let PosId = UserDefaults.standard.integer(forKey: "getPosId")
        let transaction_profile = UserDefaults.standard.string(forKey: "getTransactionProfile") ?? ""
        return (PosId, transaction_profile)
        }

third function getKeyWS

public static func getKeyWS(posId: Int) -> (rsa: String, rsa_id: Int) {

            let token = UserDefaults.standard.string(forKey: "AccessTokenLogin") ?? ""
            let headers = [
                "Authorization": "bla bla"
            ]
        
            let baseUrl = "bla bla"
            let portBPC = ":bla bla"
            let deviceGetKeyUrl = "bla bla"
        
            let Url = String(format: "bla bla")
            let serviceUrl = URL(string: Url)
            let parameterDictionary = ["bla bla": posId]
            var request = URLRequest(url: serviceUrl!)
            request.httpMethod = "POST"
            request.allHTTPHeaderFields = headers
            request.setValue("application/json; charset=utf-8", forHTTPHeaderField: "Content-Type")
            request.setValue("application/json; charset=utf-8", forHTTPHeaderField: "Accept")

            let httpBody = try? JSONSerialization.data(withJSONObject: parameterDictionary, options: [])
            request.httpBody = httpBody
        
            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)")
                }
                
                do {
                    if let convertedJsonIntoDict = try JSONSerialization.jsonObject(with: data, options: []) as? NSDictionary {
                        // Print out dictionary
                        print(convertedJsonIntoDict)
                        let response = convertedJsonIntoDict
                              guard let MainDataResponse = response["dataResponse"] as? NSDictionary else { return }
                              let rsa_id = MainDataResponse["rsaId"] as? Int ?? 0
                              let rsa = MainDataResponse["rsa"] as? String ?? ""

                         
                        UserDefaults.standard.set(rsa_id, forKey: "rsa_id")
                        UserDefaults.standard.set(rsa, forKey: "rsa")
                              

                    



                    }
                } catch let error as NSError {
                    print("catch let error")
                    print(error.localizedDescription)
                }
                }.resume()
        let rsa = UserDefaults.standard.string(forKey: "rsa") ?? ""
        let rsa_id = UserDefaults.standard.integer(forKey: "rsa_id")
        return (rsa, rsa_id)
        }

fourth function callInitDukptKeys

public static func callInitDukptKeys(pos_id: Int, rsa: String, check_value: String , crc32: String) -> (newKey: String, ksnString: String, crc32: String, checkValue: String) {

       let token = UserDefaults.standard.string(forKey: "AccessTokenLogin") ?? ""
       let headers = [
           "Authorization": "bla bla"
       ]

       let baseUrl = "bla bla"
       let portBPC = ":bla bla"
       let deviceInitDukptKeysUrll = "bla bla"
    
       let UUrl = String(format: "bla bla")
       let serviceUrlll = URL(string: UUrl)
       let parameterDictionary = ["bla bla": String(pos_id),
       "bla bla": rsa,
       "bla bla": check_value,
       "bla bla": crc32]
       var requests = URLRequest(url: serviceUrlll!)
       requests.httpMethod = "POST"
       requests.allHTTPHeaderFields = headers
       requests.setValue("application/json; charset=utf-8", forHTTPHeaderField: "Content-Type")
       requests.setValue("application/json; charset=utf-8", forHTTPHeaderField: "Accept")
    

       let httpBody = try? JSONSerialization.data(withJSONObject: parameterDictionary, options: [])
       requests.httpBody = httpBody

    _ = URLSession.shared.dataTask(with: requests) { data, response, error in
           
           guard let data = data, error == nil else {
            print("error=\(String(describing: error))")
               return
           }
           
           if let httpStatus = response as? HTTPURLResponse, httpStatus.statusCode != 200 {
               print("statusCode should be 200, but is \(httpStatus.statusCode)")
            print("response = \(String(describing: response))")
           }
           
           do {
               if let DictConvert = try JSONSerialization.jsonObject(with: data, options: []) as? NSDictionary {
                   // Print out dictionary

                   let response = DictConvert
                   let status = response["status"] as? Bool
                   if status == true {
                   let mainResponse = response["dataResponse"] as? NSDictionary
                   let getKey = mainResponse!["key"] as? String
                   let keyCheckValue = mainResponse!["keyCheckValue"] as? String
                   let keyCrc32 = mainResponse!["keyCrc32"] as? String
                   let ksn = mainResponse!["ksn"] as? String
                   
                    print("valor getKey: \(getKey)")
                    print("valor ksn: \(ksn)")
                    print("valor keyCrc32: \(keyCrc32)")
                    print("valor keyCheckValue: \(keyCheckValue)")
                    UserDefaults.standard.set(getKey, forKey: "getKey")
                    UserDefaults.standard.set(ksn, forKey: "ksn")
                    UserDefaults.standard.set(keyCrc32, forKey: "keyCrc32")
                    UserDefaults.standard.set(keyCheckValue, forKey: "keyCheckValue")
                   } else {
                       print("error")
                   }


               }
           } catch let error as NSError {
               print("catch let error")
               print(error.localizedDescription)
           }
           }.resume()
    let newKey = UserDefaults.standard.string(forKey: "getKey") ?? ""
   let ksnString = UserDefaults.standard.string(forKey: "ksn") ?? ""
   let crc32 = UserDefaults.standard.string(forKey: "keyCrc32") ?? ""
   let checkValue = UserDefaults.standard.string(forKey: "keyCheckValue") ?? ""
    
   return (newKey, ksnString, crc32, checkValue)
   }

   

ZeroCooL
  • 79
  • 5
  • `dataTask(with` works asynchonously. It's impossible to **return** the received data from a method. Never wait with hard-coded delays. Don't do that. You have to add completion handlers. And it's bad practice to (mis)use UserDefaults to save data temporarily. And don't use `NSArray/NSDictionary` in Swift. Use native types. – vadian Jan 28 '20 at 05:48
  • thanks for the response, how could i solve my problem?, if i can't use dataTask, what can i do? – ZeroCooL Jan 28 '20 at 06:14
  • You can use dataTask, but as I said you have to add completion handlers. This is a quite frequently asked question, for example see https://stackoverflow.com/questions/25203556/returning-data-from-async-call-in-swift-function – vadian Jan 28 '20 at 07:47
  • WOW tons of CLAPS, thank you so much, it work now with completion handlers – ZeroCooL Jan 28 '20 at 16:11

0 Answers0