首页 > 解决方案 > 如何在 Swift 中进行异步 api 调用

问题描述

我正在尝试进行 api 调用并在 UICollectionView cellForItemAt 函数中打印结果,但 UICollectionView 在从 api 获取数据时滞后。我尝试了集合视图预取 api,但我无法实现它。如何解决滞后滚动问题? 这是问题所在:

这是我的 api 调用类:

class ApiManager {

static var url: String?

static var header: [String : String]?

static var httpMethod: String?

static let session = URLSession.shared

static func getTask(itemName: String, completion:@escaping ([String]) -> Void) -> URLSessionDataTask {
    
    let url = URL(string: ApiManager.url!)
    
    var request = URLRequest(url: url!, cachePolicy: .useProtocolCachePolicy, timeoutInterval: 10.0)
    
    request.allHTTPHeaderFields = ApiManager.header!
    
    request.httpMethod = ApiManager.httpMethod
    
    let session = ApiManager.session
    
    let dataTask = session.dataTask(with: request) { data, response, error in
        if error == nil && data != nil {
            if (error != nil) {
                print(error!)
            } else {
                do {
                    if let dictionary = try JSONSerialization.jsonObject(with: data!, options: []) as? [[String:Any]] {
                        var itemArray = [String]()
                        
                        for index in 0...dictionary.count - 1 {
                            if let items = dictionary[index][itemName] as? String {
                                itemArray.append(items)
                            }
                        }
                        
                        completion(itemArray)
                    }
                    
                } catch {
                    
                }
            }
        }
    }
    return dataTask
}

}

这是我的 ViewController 代码:

class ViewController: UIViewController {

    @IBOutlet weak var collectionView: UICollectionView!
    
    var quoteArray = [String]()
    
    var categories = ["love", "motivational", "mothersday", "all"]
    
    override func viewDidLoad() {
        super.viewDidLoad()
        collectionView.delegate = self
        collectionView.dataSource = self
        
        for category in categories {
            ApiManager.url = "https://famous-quotes4.p.rapidapi.com/random?category=\(category)&count=1000"
        }
        ApiManager.header = ["x-rapidapi-host": "famous-quotes4.p.rapidapi.com", "x-rapidapi-key": "SECRET_API_KEY" ]
        ApiManager.httpMethod = "GET"
    
        ApiManager.getTask(itemName: "text") { items in
            DispatchQueue.main.async {
                self.quoteArray.append(contentsOf: items)
                self.collectionView.reloadData()
            }
        }.resume()
    }
}

这是我的 cellForItemAt 函数代码:

   func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
    guard let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "cell", for: indexPath) as? Cell else { fatalError("cell dequeue error") }
    
    cell.label.text = self.quoteArray[indexPath.row]
    
    return cell
}

标签: iosswiftapiuicollectionview

解决方案


推荐阅读