Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Completion handler swift 3 return a variable from function

I am confused surrounding the syntax for a completion handler in swift 3.

In the function below, after parsing an xml file from a web service call, it should return a variable (an array [String:String]).
My attempt is below, but obviously it is incorrect.

  enum HistoryKey {
  case success([String:String])
  case failure(String)
 }

 private func getHistoryKeys(searchterm: String, completion: @escaping () -> HistoryKey) {
    let url = PubmedAPI.createEsearchURL(searchString: searchterm)
    let request = URLRequest.init(url: url as URL)
    let task = session.dataTask(with: request) { (data, response, error) in

        if let theData = data{
            let myParser = XMLParser.init(data: theData)
            myParser.delegate = self
            myParser.parse()
        }
    }
    task.resume()

    if keys.isEmpty {
        return .failure("no historyKeyDictionary")
    }else{
        return .success(keys)
    }

}// End of func

I want to use this function as follows

 let result = self.getHistoryKeys(searchTerm)
like image 995
tim Avatar asked Nov 30 '22 15:11

tim


2 Answers

Two issues:

  • The completion handler passes a HistoryKey instance and has no return value so the signature must be the other way round.
  • The call of the completion handler must be inside the completion block of the data task.

To be able to parse the received data outside the completion block return the data on success

enum ConnectionResult {
   case success(Data)
   case failure(Error)
}

private func getHistoryKeys(searchterm: String, completion: @escaping (ConnectionResult) -> ()) {
   let url = PubmedAPI.createEsearchURL(searchString: searchterm)
   let task = session.dataTask(with: url) { (data, response, error) in
       if let error = error {
          completion(.failure(error))
       } else {
          completion(.success(data!))
       }
  }
  task.resume()
}

and call it

getHistoryKeys(searchterm: String) { connectionResult in 
    switch connectionResult {
       case .success(let data): 
           let myParser = XMLParser(data: data)
           myParser.delegate = self
           myParser.parse()
           // get the parsed data from the delegate methods

       case .failure(let error): print(error)
    }
}
like image 167
vadian Avatar answered Dec 05 '22 12:12

vadian


You are not using completion block.
Use it like:

private func getHistoryKeys(searchterm: String, completion: @escaping (_ keys: Array) -> Void) {
    //do the magic
    completion(keys)
}

Then you can call this function as:

getHistoryKeys(searchterm: "str") { (keys) in 
    print("\(keys)")
}
like image 41
D4ttatraya Avatar answered Dec 05 '22 12:12

D4ttatraya