【问题标题】:URLSession does not call API. Though in Playground it worksURLSession 不调用 API。虽然在操场上它有效
【发布时间】:2021-02-03 23:14:33
【问题描述】:

所以这段代码在操场上对我有用,但由于某种原因,URLSession.shared.dataTask(... 没有调用我当前在本地运行的烧瓶 api。知道出了什么问题吗?到目前为止,我只关心为什么它没有进入我的项目中的do{,但它在操场上正常工作。

    func getWords() -> [Word]{
    var words = [Word]()
    let url = URL(string: self.url)
    let request = URLRequest(url: url!)
    
    let group = DispatchGroup()
    
    print("XD")
    URLSession.shared.dataTask(with: request, completionHandler: { (data, response, error) in
            do {
                print("A")
                if let data = data{
                    print("B")
                    if let decodedResponse = try? JSONDecoder().decode([Word].self, from: data){
                        group.enter()
                        DispatchQueue.main.async(){
                            words = decodedResponse
                            print("C")
                            print(words)
                            group.leave()
                        }
                    }
                }
                print("DD")
            } catch {
                print("Words.swift Error in try catch")
            }
    group.enter()
    }).resume()
    group.leave()

    group.notify(queue: DispatchQueue.main, execute: {
           print(words)
         })
    print("ASDASD WORDS: \(words)")
    
    for _ in 1 ... 4 {
        // - to make sure there aren't duplicates -
        
        var wordId:Int = Int.random(in: 0..<words.count)
        while randomIds.contains(wordId){
            wordId = Int.random(in: 0..<words.count)
        }
        randomIds.append(wordId)
    }
    //returns 4 words
    return words
}

【问题讨论】:

  • 不要使用group.wait。调用resume前使用group.enter,调度组为空后使用group.notify { }执行代码
  • @Paulw11 感谢您的回复保罗。好的,我编辑了代码,但我的意思是这不能解决我的 API 被调用的问题吗?因为它没有。
  • 你得到什么输出?你是在模拟器上运行还是在真机上运行?
  • @Paulw11 我在 xcode 中使用模拟器。我唯一的输出是“XD”。并且使用断点我知道它不会进入'do {'。这意味着 'URLSession.shared.dataTask(' 搞砸了。
  • 你可以edit你的问题显示你当前的代码吗,因为你在当前问题代码中的调度组代码的方式是错误的,并且会由于线程阻塞而导致问题

标签: ios swift xcode api urlsession


【解决方案1】:

你没有正确使用DispatchGroup;您应该在开始异步工作之前调用enter,并在完成后调用leave。然后你可以使用notify 来执行一些操作。

但是,在这种情况下,您实际上并不需要DispatchGroup;你有这个是因为你试图把一个异步操作变成一个同步操作;

正确的做法是接受操作是异步的,这个函数不可能return[Word]。您需要重构函数以接受完成处理程序闭包并使用结果调用它。

类似这样的:

func getWords(completionHandler:@escaping (Result<[Word], Error>) -> Void)  -> Void{
    var words = [Word]()
    let url = URL(string: self.url)
    let request = URLRequest(url: url!)  // Note you should use a guard and call the completion handler with an error if url is `nil`
    
    URLSession.shared.dataTask(with: request, completionHandler: { (data, response, error) in
        if let error = error {
            completionHandler(.failure(error))
        } else {
            do {
                if let data = data {
                   let words = try JSONDecoder().decode([Word].self, from: data)
                   completionHandler(.success(words))
                } else {
                   // TODO call completionHander with a .failure(SomeError)
                }
            } catch {
                completionHandler(.failure(error))
            }
        }
    }).resume() 
}

那么你就可以调用它了:

getWords() { result in 
    switch result {
    case .success(let words):
        print(words)
    case .failure(let error):
        print(error.localizedDescription)
    }
}

【讨论】:

  • 哇,谢谢保罗。我从来没有使用过像completionHandler:@escaping (Result&lt;[Word], Error&gt;) -&gt; Void 这样的东西,把它放在函数参数中到底意味着什么? @escaping 有什么作用?所以这在技术上仍然是同步的,因为(我将假设)completionhandler 等到它被正确执行并且在completionHandler(.success(words)) 上将返回单词。
  • 您将closure(匿名代码块)传递给函数。该函数可以在有结果时执行此闭包。它不是同步的,因为没有“等待”。如果您在调用“getWords”之后有print("hi"),您将看到在打印单词之前打印了hi。 @escaping 表示函数返回后会调用闭包。
  • 我明白了。非常感谢您对保罗的所有帮助!我已将我的代码编辑为上述内容,但不幸的是,我遇到了同样的问题......它没有进行 URLSession 调用。所以它会跳过 URLSession call.resume() 之间的所有内容
  • 它不会“跳过”它。一旦网络操作完成,该代码将稍后执行。在完成处理程序闭包中设置断点。如果没有调用完成处理程序,那么您需要查看包含此函数的类。在网络操作完成之前对该类的引用是否超出范围?
  • 所以这确实有效。唯一的问题是我在调用.getWords 之后需要来自api 调用的数据。所以这个程序一直在困扰我,因为我在the network operation was complete 之前使用过它。但是现在如果我需要 .getWords 之后的数据,我该怎么做呢?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2018-01-13
  • 1970-01-01
  • 2022-01-08
  • 1970-01-01
  • 2023-03-19
  • 1970-01-01
  • 2019-03-15
相关资源
最近更新 更多