繁体   English   中英

如何调用进行 API 调用的类的实例,以及该类中发出请求的函数,并将其分配给变量? 迅速

[英]How to call an instance of a class that makes an API call, and a function within that class that makes the request, and assign this to variable? Swift

这是对以下问题的跟进: 为什么代码没有在第二个 URLSession.shared.dataTask 之后/在第二个 URLSession.shared.dataTask 之后执行,即在初始 URLSession.shared.dataTask 的 do 块内? 迅速

我正在尝试使用self.variable将变量的当前实例分配给类实例的函数调用。

这可以在附加代码的 ViewController.swift 中以“self.venues =”开头的代码行中看到。

我相信Task与此有关。 我已经阅读了有关Task的文档,并在网上阅读了更多关于它的信息,但还没有找到解决方案。

另外:我在 ViewController.swift 中以“self.venues =”开头的代码行中收到错误消息“Cannot assign value of type 'Task<(), Never>' to type '[Venue]'”。

代码:

ViewController.swift

import UIKit
import CoreLocation

class ViewController: UIViewController, UITableViewDelegate, UITableViewDataSource {
    
    @IBOutlet var tableView: UITableView!
    
    var venues: [Venue] = []
    
    override func viewDidLoad() async {
        super.viewDidLoad()
        
        tableView.register(UINib(nibName: "CustomTableViewCell", bundle: nil), forCellReuseIdentifier: "CustomTableViewCell")
        tableView.delegate = self
        tableView.dataSource = self
        
        let yelpApi = YelpApi(apiKey: "Api key")
        
        self.venues = Task {
            do { try await yelpApi.searchBusiness(latitude: selectedLatitude, longitude: selectedLongitude, category: "category quary goes here", sortBy: "sort by quary goes here", openAt: )

            }
            catch {
            //Handle error here.
            print("Error")
            }
        }
        
        DispatchQueue.main.async {
            self.tableView.reloadData()
        }
        
    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return venues.count
    }
    
    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let cell = tableView.dequeueReusableCell(withIdentifier: "CustomTableViewCell", for: indexPath) as! CustomTableViewCell
        
        //Details for custom table view cell go here.
    }
        
    //Rest of table view protocol functions.
}

Venue.swift

import Foundation

// MARK: - BusinessSearchResult
struct BusinessSearchResult: Codable {
    let total: Int
    let businesses: [Venue]
    let region: Region
}

// MARK: - Business
struct Venue: Codable {
    let rating: Double
    let price, phone, alias: String?
    let id: String
    let isClosed: Bool?
    let categories: [Category]
    let reviewCount: Int?
    let name: String
    let url: String?
    let coordinates: Center
    let imageURL: String?
    let location: Location
    let distance: Double
    let transactions: [String]

    enum CodingKeys: String, CodingKey {
        case rating, price, phone, id, alias
        case isClosed
        case categories
        case reviewCount
        case name, url, coordinates
        case imageURL
        case location, distance, transactions
    }
}

// MARK: - Category
struct Category: Codable {
    let alias, title: String
}

// MARK: - Center
struct Center: Codable {
    let latitude, longitude: Double
}

// MARK: - Location
struct Location: Codable {
    let city, country, address2, address3: String?
    let state, address1, zipCode: String?

    enum CodingKeys: String, CodingKey {
        case city, country, address2, address3, state, address1
        case zipCode
    }
}

// MARK: - Region
struct Region: Codable {
    let center: Center
}

FetchData.swift

import UIKit
import Foundation
import CoreLocation

class YelpApi {
    
    private var apiKey: String
    
    init(apiKey: String) {
        self.apiKey = apiKey
    }
    
    func searchBusiness(latitude: Double,
                        longitude: Double,
                        category: String,
                        sortBy: String) async throws -> [Venue] {
        
        var queryItems = [URLQueryItem]()
        queryItems.append(URLQueryItem(name:"latitude",value:"\(latitude)"))
        queryItems.append(URLQueryItem(name:"longitude",value:"\(longitude)"))
        queryItems.append(URLQueryItem(name:"categories", value:category))
        queryItems.append(URLQueryItem(name:"sort_by",value:sortBy))
       
        var results = [Venue]()
        
        var expectedCount = 0
        let countLimit = 50
        var offset = 0
        
        queryItems.append(URLQueryItem(name:"limit", value:"\(countLimit)"))
        
        repeat {
            
            var offsetQueryItems = queryItems
            
            offsetQueryItems.append(URLQueryItem(name:"offset",value: "\(offset)"))
            
            var urlComponents = URLComponents(string: "https://api.yelp.com/v3/businesses/search")
            urlComponents?.queryItems = offsetQueryItems
            
            guard let url = urlComponents?.url else {
                throw URLError(.badURL)
            }
            
            var request = URLRequest(url: url)
            request.setValue("Bearer \(self.apiKey)", forHTTPHeaderField: "Authorization")
            
            let (data, _) = try await URLSession.shared.data(for: request)
            let businessResults = try JSONDecoder().decode(BusinessSearchResult.self, from:data)

            expectedCount = min(businessResults.total,1000)
            
            results.append(contentsOf: businessResults.businesses)
            offset += businessResults.businesses.count
        } while (results.count < expectedCount)
        
        return results
    }
}

谢谢!

您有一个异步操作 - searchBusinesses 调用此函数时,需要时间才能得到结果。 您正在使用await来处理此问题。

您不能在异步上下文之外使用await ,而viewDidLoad不是。 您正在使用Task来创建异步上下文。 到目前为止,一切都很好。

你出错的地方是试图将结果分配给venues 您只能在await完成后执行此分配。 您不会Task获得此结果,而是Task中获得它:

Task {
    do { 
        self.venues = try await yelpApi.searchBusiness(latitude: selectedLatitude, longitude: selectedLongitude, category: "category quary goes here", sortBy: "sort by quary goes here", openAt: )
        self.tableView.reloadData()
    } catch {
            //Handle error here.
            print("Error")
    }
}

请注意,您不应该将 GCD 调度队列和 async/await 结合使用,在这种情况下,您无需担心主队列。

UIViewController被标记为@MainActor 这意味着除非您专门创建分离任务,否则任务已经在主要参与者上执行。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM