-1.8 C
New York
Thursday, February 20, 2025

ios – Tips on how to Cancel Earlier Asynchronous Requests?


Background

I am engaged on a UITableView that masses with preloaded information, then fetches extra objects asynchronously. Once I spam pull-to-refresh, every pull triggers a brand new async request, leading to a number of callbacks and duplicate objects.

I would like to make sure that:

Solely the newest loadItems() name’s async outcomes are processed.
Earlier async requests are ignored or canceled, avoiding duplicate objects.

Essential

When calling loadItems(), it may doubtlessly create a brand new occasion with the identical information every time. Nevertheless, as a result of every occasion is technically distinctive, merely checking if the merchandise already exists within the objects array earlier than including it will not work.

To deal with this, I would like a strategy to cancel any earlier pending requests every time pull-to-refresh is triggered, guaranteeing solely the newest request is processed.

Additional

I attempted checking if the merchandise already exists within the objects array earlier than including it, however this method fails as a result of loadItems() can return a brand new occasion every time, even when the info is an identical. On this instance, it is only a easy String sort, however within the precise situation, the info sort is extra advanced.

Code

import UIKit

closing class AsyncProvider {
    func loadItems(completion: @escaping ([String]) -> Void) {
        DispatchQueue.most important.asyncAfter(deadline: .now() + 5.0) {
            completion(["Async Item"])
        }
    }
}

closing class ViewController: UIViewController, UITableViewDataSource {
    non-public let tableView = UITableView()
    non-public var objects: [String] = ["Item A", "Item B", "Item C"] // Preliminary objects
    non-public var hasReloaded = false
    non-public let asyncProvider = AsyncProvider()
    non-public let refreshControl = UIRefreshControl() // Pull-to-refresh management

    override func viewDidLoad() {
        tremendous.viewDidLoad()
        
        // Fundamental desk view setup
        tableView.dataSource = self
        view.addSubview(tableView)
        tableView.body = view.bounds
        
        // Arrange pull-to-refresh management
        refreshControl.addTarget(self, motion: #selector(refreshTableView), for: .valueChanged)
        tableView.refreshControl = refreshControl
        
        // Preliminary information load
        loadItems()
    }
    
    // Pull-to-refresh motion
    @objc non-public func refreshTableView() {
        loadItems()
        refreshControl.endRefreshing() // Finish the refresh animation
    }
    
    // Load extra async objects
    non-public func loadItems() {
        asyncProvider.loadItems { [weak self] newItems in
            guard let self = self else { return }
            
            if self.hasReloaded {
                self.objects.insert(contentsOf: newItems, at: 0)
                self.tableView.performBatchUpdates({
                    self.tableView.insertSections(IndexSet(integer: 0), with: .computerized)
                }, completion: nil)
            } else {
                self.objects.append(contentsOf: newItems)
            }
        }
        
        self.hasReloaded = true
        tableView.reloadData()
    }
    
    func numberOfSections(in tableView: UITableView) -> Int {
        return objects.depend
    }
    
    func tableView(_ tableView: UITableView, numberOfRowsInSection part: Int) -> Int {
        return 1
    }
    
    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let cell = UITableViewCell(type: .default, reuseIdentifier: "cell")
        cell.textLabel?.textual content = objects[indexPath.section]
        return cell
    }
}

Related Articles

LEAVE A REPLY

Please enter your comment!
Please enter your name here

Latest Articles