I'm new to swift and iOS Development. I want have 100 cells in my UITableView and each cell has a different API request that returns JSON data which I will save to the CoreData and then display in the UITableView. How do i handle this? I want to implement lazy loading but i have no idea how to do it in this case. Please point me to the right direction.
You Can loading table view in main_queue
//Use swift 2.3
dispatch_async(dispatch_get_main_queue(), { () -> Void in
self.yourTableView.reloadData()
})
//Use swift 3
DispatchQueue.main.async{
self.yourTableView.reloadData()
}
Related
I have a horizontal scrolling collection view inside a UITableView cell, achieving the view same as that of Netflix.
Currently, I am loading URL data in my view controller containing table view and passing the array of data in UITableViewCell which contains the collectionView, and then rendering collection view cells.
But I'm feeling lack of controls using this method. For e.g, UI management, hiding, showing views depending on URL data load and error, etc.
I tried loading URL data inside table view cell and that works
perfectly fine for me but I don't think that's appropriate to do, as
only controllers should control everything.
The closure I'm using to load data in my controller is -
private func fetchData() {
let id = UserDefaults.standard.getUserId()
Service.shared.fetch(userId: id) { (data, error) in
DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + 0.5, execute: {
guard error == nil else {
print(error?.localizedDescription ?? "Error")
return
}
let result = data?.count != 0 ? "Success" : "Failure"
switch result {
case ResultType.Failure.rawValue:
print("Failure")
case ResultType.Success.rawValue:
if let data = data {
self.data = data
}
default: break
}
})
}
}
Back to the Question, Is it fine loading the data inside
UITableViewCell in order to hide/show or animate UICollectionView inside that UITableViewCell?
Moreover, Assume a scenario where I have to load 4-5 URL data and render them in each custom table view cell which may or may not contain a collection view.
Complicated!
You can load data in a view, but it wouldn’t be a good architecture. It hampers reusabilty and mixes responsibilities. Also, table view cells will be reused, which will eventually lead to weird data loading behavior and probably bugs.
I suggest extracting data loading into a custom class, and using that class in the view controller. This way your data loading is decoupled from the controller and the view, giving the most flexibility.
I face one issue of displaying data in the table view. It works fine when I scrolling down and back to the top. I have also table reload in the main queue but it's not working for me. I have referred following link but not getting any solution.
showing-first-time-only-when-scrolling-a-bit Table view cells showing actual data only after scrolling once
I have also reloaded table viewdidapear and also when I got data from the API.
DispatchQueue.main.async {
self.tblDashboard.refreshControl?.endRefreshing()
self.tblDashboard.reloadData()
}
Please find the attached video for the understanding (click here for video) and please see the code files here.
Strange !!
if let aTempArr = result["songs"] as? [[String : Any]] {
//// parsing code here ......
self.tblDashboard.reloadData() ///<---
}
DispatchQueue.main.async {
self.tblDashboard.refreshControl?.endRefreshing()
self.tblDashboard.reloadData()
}
Also, I move the cell method's code into the cellForRowAt indexPath in Tableview controller.
I'm trying to implement a tableView that has 4 different possible prototype cells. They all inherit from base UITableViewCell class and implement its protocol.
For two of the cells there's asynchronous data fetching but one in particular has been giving me fits. The flow is as follows:
1) Dequeue reusable cell
2) Call configure
func configure(someArguments: ) {
//some checks
process(withArguments: ) { [weak self in] in
if let weakSelf = self {
weakSelf.reloadDelegate.reload(forID: id)
}
}
}
3) If the async data is in the cache, configure the cell using the image/data/stuff available and be happy
4) If the async data is NOT in the cache, fetch it, cache it, and call the completion
func process(withArguments: completion:) {
if let async_data = cache.exists(forID: async_data.id) {
//set labels, add views, etc
} else {
fetch_async_data() {
//add to cache
//call completion
}
}
}
5) If the completion is called, reload the row in question by passing the index path up to the UITableViewController and calling reloadRows(at:with:)
func reload(forID: ) {
tableView.beginUpdates()
tableView.reloadRows(at: indexPath_matching_forID with: .automatic)
tableView.endUpdates()
}
Now, my understanding is that reloadRows(at:with:) will trigger another dataSource/delegate cycle and thus result in a fresh resuable cell being dequeued, and the configure method being called again, thereby making step #3 happy (the async data will now be in the cache since we just fetched it).
Except...that's not always happening. If there are cells in my initial fetch that require reloading, it works - they get the data and display it. Sometimes, though, scrolling down to another cell that requires fetching DOES NOT get the right data...or more specifically, it doesn't trigger a reload that populates the cell with the right data. I CAN see the cache being updated with the fresh data, but it's not...showing up.
If, however, I scroll completely past the bad cell, and then scroll back up, the correct data is used. So, what the hell reloadRows?!
I've tried wrapping various things in DispatchQueue.main.async to no avail.
reloadData works, ish, but is expensive because of potentially many async requests firing on a full reload (plus it causes some excessive flickering as cells come back)
Any help would be appreciated!
Reused cells are not "fresh". Clear the cell while waiting for content.
func process(withArguments: completion:) {
if let async_data = cache.exists(forID: async_data.id) {
//set labels, add views, etc
} else {
fetch_async_data() {
// ** reset the content of the cell, clear labels etc **
//add to cache
//call completion
}
}
}
I am building an iOS app and I am trying to implement a pull-down refresh control on my project. The data is fetched correctly from an API and displayed on my table. But the problem rises when I do pull down to refresh. The following situations happen:
If I pull down for a long distance from the top, and the tableview.reloadData() function is called, the cells in the non-visible portion of the table come with the default tableview cells on top of them, overlapping...
if I pull down multiple times in quick succession the same issue happens.
I believe that it is because tableview.reloadData() is called multiple times in quick succession. But why are the default cells getting dequeued on top of my custom cells? Here is the section of code in the function to handle the pulldown:
#objc func refreshFunc(){
//let offset = scrollView.contentOffset.y
if myRefreshControl.isRefreshing{
readJson { (activities) in
self.activities = activities
self.tableView.reloadData()
self.myRefreshControl.endRefreshing()
}
}
}
Any help would be appreciated. Thanks in advance
UPDATE:
Changing the code to the code below seems to remove the error, but the problem is that now I need to pull down twice in order to get the results updated on the table:
#objc func refreshFunc(){
readJson { (activities) in
self.activities = activities
}
self.tableView.reloadData()
self.myRefreshControl.endRefreshing()
}
Please note that running the reloadData on the main thread gives the same result, I still need to pull down twice to update.
Please try to give some delay before refresh table view may it resolve your problem.
DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + delayTime) { [weak self] in
self?.tableView.reloadData()
}
Hope it works
Cheers :)
DispatchQueue.main.async {
self.tableView.reloadData
}
Try this, always, if u want change UI you have to call on main thread
how is it possible to reload data for a cell in my table view? I want to do a request to my Server and the server responses JSON. At the moment I implemented the request and the response handling and I can show the data in my cells. But I want that the server only responses maybe ten datasets. When I scroll to the end of the table view with my ten cells in the app I want to do the next request to my server and the server delivers the next ten datasets and so on. I work with Swift as the programming language.
THX!
You can use self.tableView.reloadData() in order to reload your entire table or self.tableView.reloadRowsAtIndexPaths(paths, withRowAnimation: UITableViewRowAnimation.None) in order to reload a specific cell.
You can read more about the UITableView class here
To reload visible cells of tableview in Swift 3.0
pTableView.beginUpdates()
pTableView.reloadRows(at: pMessagesTableView.indexPathsForVisibleRows!, with: .none)
pTableView.endUpdates()
Try this...
Swift 2.0
dispatch_async(dispatch_get_main_queue(), { () -> Void in
self.tableView.reloadData()
})
Swift 3.0
DispatchQueue.main.async {
self.tableview.reloadData()
}
you can get Array of visible Cell by using TableView Function tableView.visibleRows() or You Can Get IndexPath of Visible Rows By tableView.indexPathsForVisibleRows() ! and then you can reload table by tableView.reloadData() Function!
look at following links
link1
you can read about UITableView Class Here