Reputation: 754
I tried to run a simple code which is running perfectly on iOS 14/15/16, but now while using Xcode 15 on iOS 17 this is not working anymore. I will attach the code below displaying a table view with a UIRefreshControl
which will run beginRefreshing()
before a fetch request, but the refresh control is not showing anymore on iOS 17 and I'm getting this warning which is saying that the refresh control received offscreen beginRefreshing.
Here is the code with a simulated fetch request using DispatchQueue.main.asyncAfter
displaying a simple table view. If you try to run it on iOS 17, the refresh control will not be displayed before the simulated fetch request.
class ViewController: UIViewController, UITableViewDataSource, UITableViewDelegate {
private let tableView = UITableView()
private let cellIdentifier = "cellIdentifier"
private let data = ["Cell 1", "Cell 2"]
private let refreshControl = UIRefreshControl()
override func viewDidLoad() {
super.viewDidLoad()
configureTableView()
refreshControl.beginRefreshing()
// Simulate fetch request
DispatchQueue.main.asyncAfter(deadline: .now() + 1, execute: {
self.setDataSource()
})
}
private func configureTableView() {
tableView.register(UITableViewCell.self, forCellReuseIdentifier: cellIdentifier)
refreshControl.addTarget(self, action: #selector(refreshData), for: .valueChanged)
tableView.refreshControl = refreshControl
tableView.frame = view.bounds
tableView.autoresizingMask = [.flexibleWidth, .flexibleHeight]
view.addSubview(tableView)
}
private func setDataSource() {
tableView.dataSource = self
tableView.reloadData()
refreshControl.endRefreshing()
}
// MARK: - UITableViewDataSource
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return data.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: cellIdentifier, for: indexPath)
cell.textLabel?.text = data[indexPath.row]
return cell
}
// MARK: - Refresh Control Action
@objc private func refreshData() {
DispatchQueue.main.asyncAfter(deadline: .now() + 2.0) {
self.refreshControl.endRefreshing()
self.tableView.reloadData()
}
}
}
Do you know any fix for this in order to run the same way even on iOS 17, without using viewDidAppear
or viewWillAppear
methods, because I want the fetch to be called only once per view life cycle?
Upvotes: 4
Views: 1500
Reputation: 381
With iOS 17, apple introduced a new lifecycle method: viewisappearing, it also has iOS 13+ backwards compatibility.
refreshControl.beginRefreshing() should be called in viewIsAppearing https://developer.apple.com/documentation/uikit/uiviewcontroller/4195485-viewisappearing
Upvotes: 8