完成处理程序 swift 3 从函数返回一个变量

Posted

技术标签:

【中文标题】完成处理程序 swift 3 从函数返回一个变量【英文标题】:Completion handler swift 3 return a variable from function 【发布时间】:2017-05-23 10:02:38 【问题描述】:

我对 swift 3 中完成处理程序的语法感到困惑。

在下面的函数中,从 Web 服务调用解析 xml 文件后,它应该返回一个变量(array [String:String])。 我的尝试如下,但显然是不正确的。

  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

我想使用这个功能如下

 let result = self.getHistoryKeys(searchTerm)

【问题讨论】:

@EricAya 他没有尝试从函数返回值,而是将其传递给另一个完成处理程序。 您的权利。我没有注意到这一点。 @EricAya 请采纳答案,让其他人更快找到。谢谢。按寒鸦 【参考方案1】:

两个问题:

完成处理程序传递一个HistoryKey 实例并且没有返回值,因此签名必须相反。 完成处理程序的调用必须数据任务的完成块内。

为了能够在完成块之外解析接收到的数据,成功时返回data

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()

并称之为

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)
    

【讨论】:

抱歉,我刚刚添加了一个编辑,以说明我想如何使用该功能。您的解决方案适用于上述情况吗? 不,它没有。要么您必须返回收到的Data,因为解析器异步工作并在函数外部解析 XML,或者您必须将完成处理程序分配给一个变量以获得强引用并从 XMLParser 委托方法调用完成处理程序。顺便说一句:枚举情况下的 array 是字典。 PS:我更新了答案以在完成处理程序中传递接收到的数据。将处理 XML 解析器结果的代码放入解析器委托方法中。 我了解您的解决方案 - 从委托方法获取变量,例如 parserDidEndDocument。但是,你能告诉我如何从 parserDidEndDocument 调用完成处理程序吗?【参考方案2】:

您没有使用completion 块。 像这样使用它:

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

那么你可以调用这个函数为:

getHistoryKeys(searchterm: "str")  (keys) in 
    print("\(keys)")

【讨论】:

【参考方案3】:

斯威夫特 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;
    

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

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

)

【讨论】:

【参考方案4】:

在完成处理程序中将结果作为参数返回:

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()   

然后这样称呼它:

getHistoryKeys("searchMe")  (result: HistoryKey) in
    print(result)

【讨论】:

抱歉,我刚刚添加了一个编辑,以说明我想如何使用该功能。您的解决方案适用于上述情况吗?因为你的返回值是 void 没有。 self.getHistoryKeys(searchTerm) 立即返回,但您的下载需要时间。你必须等待它。【参考方案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

类似的东西。更改@escaping 声明并完成而不是返回。

希望对你有帮助。

【讨论】:

【参考方案6】:

据我所见,应该是

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

还应使用completion(.failure("no historyKeyDictionary"))completion(.success(keys)) 而不是return

【讨论】:

以上是关于完成处理程序 swift 3 从函数返回一个变量的主要内容,如果未能解决你的问题,请参考以下文章

swift 3完成处理程序返回字符串

swift - 如何从系统函数的完成处理程序闭包中返回?

Swift:带有完成处理程序的多线程

来自完成处理程序的 Swift 显示视图控制器

Swift 4 将参数添加到 URLRequest 完成处理程序

Swift - 从闭包内返回变量