I am using Alamofire to get data from a web URL(JSON). I am trying to implement pull to RefreshControl into my project. I have done it but don't know if it is correct or if the data is getting updated when refreshed. My code is:
var refresh = UIRefreshControl()
refresh.addTarget(self, action: #selector(self.refreshData), for: UIControlEvents.valueChanged)
func refreshData() {
Alamofire.request("https://www.example.com/api").responseJSON(completionHandler: {
response in
self.parseData(JSONData: response.data!)
self.tableView.separatorStyle = UITableViewCellSeparatorStyle.singleLine
self.tableView.reloadData()
self.refresh.endRefreshing()
})
}
Is this correct?
You are doing correctly but you need reload tableView and stop UIRefreshControl on main thread.
DispatchQueue.main.async {
self.tableView.reloadData()
self.refresh.endRefreshing()
}
Note: Instead of setting separatorStyle always on API request you need to set it once with viewDidLoad or with Interface builder.
Related
I'm trying to add pull to refresh on my wkwebview app. I'm using UIViewRepresentable for my webview, so I don't have the onViewLoad function and view controllers. Here's my code:
var wbWebViewEl: WKWebView = WKWebView()
struct SwiftUiWebView: UIViewRepresentable {
....
class refreshWebViewClass {
#objc func refreshWebView1(sender: UIRefreshControl) {
print("test debug :D")
wbWebViewEl.reload()
DispatchQueue.main.async {
sender.endRefreshing()
}
}
func makeUIView(context: Context) -> WKWebView {
......
wbWebViewEl.scrollView.bounces = true
let refreshControl = UIRefreshControl()
refreshControl.addTarget(self, action: #selector(refreshWebViewClass.refreshWebView1), for: UIControl.Event.valueChanged)
wbWebViewEl.scrollView.addSubview(refreshControl)
wbWebViewEl.scrollView.refreshControl = refreshControl
.....
}
.....
}
At the moment, when you swipe down, it shows the refresh loading spinner, but it doesn't stop spinning. Also the test print I put in the refreshWebView1 function, doesn't show in the logcat. Does anyone know what I'm getting wrong here? If you need to see anymore code let me know :)
Looks like your refreshWebViewClass should be a Coordinator. Then, in your addTarget, the target would be context.coordinator, not self, which doesn't make sense here, since self doesn't actually implement this method.
I'm using UITableView with UIRefreshControl in my UIViewController. When user pulls down the UITableView, UIRefreshControl it works fine. Problem occurs when the data is being fetched. After successful fetching i want UIRefreshControl to stop animate and reload data in the table view.
Video related
The thing is that when I do it as below animation flickers, jumps and god know what else.
private func setupActions() {
mainView.refreshControl.addTarget(self, action: #selector(fetchSurveys), for: .valueChanged)
}
#objc private func fetchSurveys() {
viewModel.fetchSurveys(success: { [weak self] in
self?.mainView.configureEmptyTableView(isHidden: false)
self?.mainView.refreshControl.endRefreshing()
self?.mainView.tableView.reloadData()
}, failure: { [weak self] error in
self?.mainView.configureEmptyTableView(with: "Unable to fetch surveys. Please try again.", isHidden: true)
self?.mainView.refreshControl.endRefreshing()
})
}
I've tried many combinations of order of reloadData() and endRefreshing() and still it doesn't work correctly.
I have a UITableView, that on the delegate of the UIViewController that adds a new item, inserts the row. The row gets correctly inserted.
However, the UIRefreshControl on the UITableView will not go away when dragging the UITableView after that.
extension FeedViewController: AddPostDelegate {
func didAddPost(_ userPost: UserPost) {
self.postsWrapper?.posts.insert(PostWrapper(type: PostType.user(userPost)), at: 0)
self.tableView.beginUpdates()
self.tableView.insertRows(at: [
IndexPath(row: 1, section: 0)
], with: .automatic)
self.tableView.endUpdates()
self.refresher.endRefreshing()//Does nothing
}
}
In viewDidLoad:
refresher = UIRefreshControl()
tableView.addSubview(refresher)
refresher.addTarget(self, action: #selector(didDragScrollView), for: .valueChanged)
refresher.layer.zPosition = -1//otherwise in front of the header cell when refreshing (iOS 9.2)
If I do not go to another view first than come back before attempting to pull for refresh, it always hangs spinning forever.
EDIT:
It looks like the UIRefreshControl is no longer calling the target function AFTER I add a post.
Any ideas on why this may be occurring? How to fix that?
Make sure that beginRefreshing() was not called before the user pulled to refresh. If refreshControl.isRefreshing is true then the selector does not get called upon "pull to refresh".
A simple test:
let refreshControl = UIRefreshControl()
override func viewDidLoad() {
super.viewDidLoad()
refreshControl.addTarget(self, action: #selector(ViewController.refreshData), for: .valueChanged)
tableView.refreshControl = refreshControl
}
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
// sets refreshControl.isRefreshing to true
// before the user initiates it
refreshControl.beginRefreshing()
}
Then the user pulls to refresh. Because refreshControl.isRefreshing is true the selector will not get called. If you remove refreshControl.beginRefreshing()in viewDidAppear, the selector will get called:
#objc func refreshData() {
print("refresh initiated")
refreshControl.endRefreshing()
}
Try assigning your UIRefreshControl into the refreshControl property of UITableView like this:
if #available(iOS 10.0, *) {
tableView.refreshControl = refresher
} else {
tableView.addSubview(refresher)
}
Note that this requires iOS 10.0 or higher, but we're soon getting iOS 12.0 so I don't think you should support iOS lower than 10.0
I need help fixing this issue! I am adding pull to refresh to my table view. When I pull to refresh I want the articles to refresh. If someone who knows this would help me would be great, and if there is anything else wrong too.
Argument of '#selector' does not refer to an '#objc' method, property, or initializer
The error is here:
refreshControl.addTarget(self, action: #selector(fetchArticles(fromSource: source)), for: .valueChanged)
return refreshControl
}()
Here is the function fetchArticles:
#objc func fetchArticles(fromSource provider: String){
...
}
You have to add another function to refresh articles, because you are passing a parameter:
#objc func refreshArticles() {
self.fetchArticles(fromSource: self.source))
}
And addTarget like this:
refreshControl.addTarget(self, action: #selector(refreshArticles), for: .valueChanged)
Also, Do not miss to add refreshControl to tableView, as such:
tableView.addSubview(refreshControl)
Update Add following line once fetchArticles completes, as such:
refreshControl.endRefreshing()
You are using session.dataTask so this must go inside:
DispatchQueue.main.async {
refreshControl.endRefreshing()
}
So I have enabled refreshing for the table view in Storyboard and put this code into the viewDidLoad() :
refreshControl?.addTarget(self, action: #selector(ViewController.refresh(sender:)), for: .valueChanged)
and this is the refresh function:
func refresh(sender: AnyObject) {
print("a")
self.tableView.reloadData()
refreshControl?.endRefreshing()
}
The problem is that when I pull to refresh, it does not print "a"(put this for testing) and it does not end refreshing. Why?
Since you're already using Storyboards, try connecting your refresh control through IBActions (valueChanged) and see if it works. Follow this link for a guide