可以将文章内容翻译成中文,广告屏蔽插件可能会导致该功能失效(如失效,请关闭广告屏蔽插件后再试):
问题:
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)
回答1:
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)
}
}
回答2:
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)")
}
回答3:
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:
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
})
回答5:
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.
回答6:
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