Completion handler swift 3 return a variable from

2020-07-23 04:16发布

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)

6条回答
在下西门庆
2楼-- · 2020-07-23 04:29
 enum HistoryKey {
    case success([String: String])
    case failure(String)
 }

 private func getHistoryKeys(searchterm: String, completion: @escaping (_ result: HistoryKey) -> Void) {
    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()
        }

        if keys.isEmpty {
            completion(.failure("no historyKeyDictionary"))
        } else {
            completion(.success(keys))
        }
    }
    task.resume()    
} // End of func

Something like that. Change @escaping declaration and do a completion instead of return.

Hope it helps.

查看更多
Melony?
3楼-- · 2020-07-23 04:31

Return the result as an argument in the completion handler:

private func getHistoryKeys(searchterm: String, completion: @escaping (result: HistoryKey) -> Void) {
    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()
        }

        //DispatchQueue.main.async { // if you want to do UI stuff dispatch calls to completion() on the main queue
        if keys.isEmpty {
            completion(.failure("no historyKeyDictionary"))
        } else{
            completion(.success(keys))
        }
        //}
    }
    task.resume()   
}

And call it like this:

getHistoryKeys("searchMe") { (result: HistoryKey) in
    print(result)
}
查看更多
迷人小祖宗
4楼-- · 2020-07-23 04:32

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)
    }
}
查看更多
劳资没心,怎么记你
5楼-- · 2020-07-23 04:39

From what I can see, it should be

private func getHistoryKeys(searchterm: String, completion: @escaping (HistoryKey) -> ())

Also completion(.failure("no historyKeyDictionary")) or completion(.success(keys)) should be used instead of return

查看更多
smile是对你的礼貌
6楼-- · 2020-07-23 04:46

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)")
}
查看更多
在下西门庆
7楼-- · 2020-07-23 04:51

Swift 4.2

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

func myFunction(str: String, completionHandler: @escaping (HistoryKey) -> ()){
     completion(.success([String:String]))
     //OR
     completion(.failure(""))
}

myFunction(str: String) { result in 
    switch result {
       case .success(let data): break;
       case .failure(let error): break;
    }
}

OR

func myFunction(str: String, completionHandler: @escaping (String) -> ()){
     completionHandler("")
} 

myFunction(str: "someThing", completionHandler: {(str) in

})
查看更多
登录 后发表回答