ios 在URLSession相关代码Swift中获得“无法在范围内找到”数据“”错误消息

8aqjt8rx  于 2023-03-05  发布在  iOS
关注(0)|答案(2)|浏览(134)

我正在尝试将某个文件中的escaping closure代码转换为async-await代码,更具体地说,我正在尝试不使用completionHandler的方式来使用这个文件中的URLSession.shared.dataTask代码行(具体地说,就是我正在使用的文件中的"URLSession.shared.dataTask(with: request) {"代码行)。
在我正在进行更改的文件中,我收到错误:代码行为"Cannot find 'data' in scope":"let json = try JSONSerialization.jsonObject(with: data!, options: [])"。
我想我得到这个错误是因为我从来没有在文件中进一步定义"data"。我没有在文件中得到这个问题,它使用escaping closure作为文件函数中的整个代码,并使用completionHandler作为"URLSession.shared.dataTask"行代码(具体来说就是"URLSession.shared.dataTask(with: request) { (data, response, error) in")。因此,在我正在使用的文件中,我在其中看到了这个错误消息,我尝试了一些解决方案,在"URLSession.shared.dataTask(with: request) {"代码行之后创建了"data"变量,并尝试了两种不同的变量赋值,但是没有一个成功。这些解决方案的尝试和我得到的错误是在下面的代码片段中。我在我工作的文件中做了这些解决方案的尝试,并且我有这个错误消息,它是File1-GetsDataNotUsingEscapingClosureAndNotUsingCompletionHandlerForURLSession.shared.dataTaskCode.swift,它们包含在下面的文件中,并被注解掉。
我原本以为data变量是在当前显示错误消息的代码行之前创建的(这一行代码在File1-GetsDataNotUsingEscapingClosureAndNotUsingCompletionHandlerForURLSession.shared.dataTaskCode.swift中是"let json = try JSONSerialization.jsonObject(with: data!, options: [])"),因此代码可能是正确的,可以正常工作,错误消息也会消失。
如何解决此错误?
我已经包含了我当前正在使用的文件,该文件具有上述错误,并且未使用escaping closure执行操作的方式,也未在URLSession.shared.dataTask代码行中使用completionHandler(具体为"URLSession.shared.dataTask(with: request) {"),命名为File1-GetsDataNotUsingEscapingClosureAndNotUsingCompletionHandlerForURLSession.shared.dataTaskCode.swift。我还包括了标记为"Solution Attempt Version 1"等的解决方案尝试,并且包括在运行该文件中具有该解决方案尝试的代码之后显示的错误。
我还包含了使用escaping closure方法的原始文件,其中在URLSession.shared.dataTask代码行中使用了completionHandler(具体为"URLSession.shared.dataTask(with: request) { (data, response, error) in"),命名为File2-GetsDataUsingEscapingClosureAndCompletionHandlerForURLSession.shared.dataTaskCode.swift

    • 代码:**

File1-GetsDataNotUsingEscapingClosureAndNotUsingCompletionHandlerForURLSession.shared.dataTaskCode.swift

import Foundation
import UIKit
import CoreLocation

extension UIViewController {

    func retrieveSelectedRestaurantDetailViewInfo(
        selected_restaurant_business_ID: String) async throws -> SelectedRestaurantDetailViewInfoNotUsingCodable? {

            // MARK: Make API Call
            let apiKey = "API key"

            /// Create URL
            let baseURL =
            "https://api.yelp.com/v3/businesses/\(selected_restaurant_business_ID)"

            let url = URL(string: baseURL)

            /// Creating Request
            var request = URLRequest(url: url!)
            request.setValue("Bearer \(apiKey)", forHTTPHeaderField: "Authorization")
            request.httpMethod = "GET"

            ///Initialize session and task
            //Code for not using completionHandler:
            URLSession.shared.dataTask(with: request) {
                
                //Solution Attempt 1: Version of code for creating "data" variable, where the variable assignment is set to "Data".
                //Got the error message for the above line of code "URLSession.shared.dataTask(with: request) {", saying "Contextual type for closure argument list expects 3 arguments, which cannot be implicitly ignored" with a "Fix" button below, and the text to the left of the "Fix" button being: "Insert '_,_,_ in '".
//                var data = Data
                
                //Solution Attempt 2: Version of code for creating "data" variable, where the variable assignment is set to "Data?".
                //Got the same error message as Solution Attempt 1; Got the error message for the above line of code "URLSession.shared.dataTask(with: request) {", saying "Contextual type for closure argument list expects 3 arguments, which cannot be implicitly ignored" with a "Fix" button below, and the text to the left of the "Fix" button being: "Insert '_,_,_ in '".
//                var data = Data?
                
                do {
                    /// Read data as JSON
                    //The line of code below is where I'm getting the error message: "Cannot find 'data'" in.
                    let json = try JSONSerialization.jsonObject(with: data!, options: [])

                    /// Main dictionary
                    guard let responseDictionary = json as? NSDictionary else {return}

                    //Code for accessing restaraunt detail view info, and assigning it to selectedRestarauntDetailViewInfo view model thats a struct.
                    var selectedVenue = SelectedRestaurantDetailViewInfoNotUsingCodable()
                    
                    
                    //Rest of code for accessing restaraunt detail view info, and assigning it to seelctedRestarauntDetailViewInfo view model thats a struct.
                    selectedVenue.name = responseDictionary.value(forKey: "name") as? String
                    
                    //*Rest of code for getting business info including address, hours, etc..*
                    
                    return selectedVenue
                    
                } catch {
                    print("Caught error")
                }
                }.resume()
    }
}

File2-GetsDataUsingEscapingClosureAndCompletionHandlerForURLSession.shared.dataTaskCode.swift

import Foundation
import UIKit
import CoreLocation

extension UIViewController {

    func retrieveSelectedRestaurantDetailViewInfo(
        selected_restaurant_business_ID: String,
        completionHandler: @escaping (SelectedRestaurantDetailViewInfoNotUsingCodable?, Error?) -> Void) {
            
            // MARK: Make API Call
            let apiKey = "API key"

            /// Create URL
            let baseURL =
            "https://api.yelp.com/v3/businesses/\(selected_restaurant_business_ID)"

            let url = URL(string: baseURL)

            /// Creating Request
            var request = URLRequest(url: url!)
            request.setValue("Bearer \(apiKey)", forHTTPHeaderField: "Authorization")
            request.httpMethod = "GET"

            ///Initialize session and task
            //Code for using completionHandler:
            URLSession.shared.dataTask(with: request) { (data, response, error) in

                if let error = error {
                    completionHandler(nil, error)
                }
                
                do {
                    /// Read data as JSON
                    let json = try JSONSerialization.jsonObject(with: data!, options: [])

                    /// Main dictionary
                    guard let responseDictionary = json as? NSDictionary else {return}

                    //Code for accessing restaraunt detail view info, and assigning it to selectedRestarauntDetailViewInfo view model thats a struct.
                    var selectedVenue = SelectedRestaurantDetailViewInfoNotUsingCodable()
                    
                    
                    //Rest of code for accessing restaraunt detail view info, and assigning it to seelctedRestarauntDetailViewInfo view model thats a struct.
                    selectedVenue.name = responseDictionary.value(forKey: "name") as? String
                    
                    //*Rest of code for getting business info including address, hours, etc..*
                    
                    completionHandler(selectedVenue, nil)
                    
                } catch {
                    print("Caught error")
                }
                }.resume()
    }
}

谢谢!

kb5ga3dv

kb5ga3dv1#

旧样式dataTask的转换如下:

URLSession.shared.dataTask(with: request) { (data, response, error) in
    if let data {
        // do stuff with the non-optional data
    else if let error {
    }
}.resume()

致:

let (data, response) = try await URLSession.shared.data(for: request)
// do stuff with the non-optional data and/or response

不再涉及需要恢复的任务。数据和响应是直接返回值(作为元组)。
这是有效的,因为您是从声明为async throws的函数内部调用它的,所以如果对data的调用抛出错误,它将传播到调用者。

jw5wzhpr

jw5wzhpr2#

在工作版本中,URLSession在调用闭包时将数据对象传递到闭包中:

URLSession.shared.dataTask(with: request) { (data, response, error) in

这就是为什么你可以访问它。这在方法签名中很明显

func dataTask(
    with url: URL,
    completionHandler: @escaping @Sendable (Data?, URLResponse?, Error?) -> Void
) -> URLSessionDataTask

在async/await中,数据直接从方法返回,但不引用返回的数据,需要修改代码以:

let (data, response) = try await URLSession.shared.data(with: request)

然后,您将能够使用所提供的data作为后续代码,就像您之前在闭包中所做的那样。

相关问题