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.
Related
Im trying to upload a post on firebase which contains: one thumbnail image, and unlimited subposts (like the content of the thumbnail). I have 3 steps on posting the pictures.
1: handle the upload image task.
2: create a "bulkUpload" function that creates image paths for each subpost.
3: call the "bulkUpload" (which also calls the upload image task)
The structure looks something like this:
(postid) {
author: (author)
likes: (number)
pathToImage: (path)
postId: (id)
subposts {
(id): (path)
(id): (path)
...etc
}
userId: (userid)
}
Simple and gets it working. But, not really. There is a strange problem that occurs with the subposts.
When I post the post, everything works, except for the subposts. The subposts, when posting the set of images for the first time, don't show.
Without adding or removing subposts, I tried posting for the second time, this time, the subposts do show. But double the amount I selected in the picker and what shows in the imageViews.
I will link the code from pastebin since its a little lengthy (and stackoverflow doesn't like a lot of code).
But hope I can get this working.
https://pastebin.com/rpLZT6nm
#Matt is right, in your case you should update your data model, which is presented by the collectionView and call reloadData or reloadItems(at:)
self.updateModel();
self.collectioView.reloadData()
self.collectioView.reloadItems(at: [IndexPath(item: 0, section: 0)]);
But if you need direct acces to visible cells, you can use other workflow:
let image : UIImage? = nil
let path = IndexPath(item: 0, section: 0)
let visiblePaths = self.collectioView.indexPathsForVisibleItems
if visiblePaths.contains(path) {
if let cell = self.collectioView.cellForItem(at: path) as? UploadSubPostCell {
cell.previewStep.image = image;
}
}
You can use such workflow to update only visible cells, because invisible cells will be reused before show to the screen
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 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
I'm following tutorial from raywenderlich (How To Make A Swipeable Table View Cell With Actions) site, that shows you how to create custom cell with layers and delegate.
Now I got everything working correctly, buy I would like one of my cells to close if other cell open, how can I achieve this? or Like Messenger app, don't allow users to open another cell option unless they close the current one.
I can't wrap my head around this, I see few other people also ask the same question in comments, but no one reply.
Anyone with Objective-C knowledge, it's okay, I can translate it to swift myself.
The reason I'm using this tutorial, is because the Apple API doesn't allow custom button (using PaintCode) to be used as Action button.
I find a very simple solution for anyone else who trying to achieve the same method.
Create a Method - closeOtherCells:
Since we store all cells in NSMutableSet we can see which ones are available for closing.
func closeOtherCells(close close: Bool){
if close{
//Check For Available Cell
for cells in cellsCurrentEditing {
//Get Table Cells at indexPath
var cellToClose: CustomTableViewCell = self.tableView.cellForRowAtIndexPath(cells as! NSIndexPath) as! CustomTableViewCell
//Call Reset Method in our Custom Cell.
cellToClose.resetConstraintContstantsToZero(true, notifyDelegateDidClose: true)
}
}
}
Now Simply in your cellDidOpen: delegate method call closeOtherCells: with true parameter.
func cellDidOpen(cell: UITableViewCell) {
//Close Other Cells
closeOtherCells(close: true)
//Store Open Cell in NSMutableSet
let indexPath: NSIndexPath = self.tableView.indexPathForCell(cell)!
self.cellsCurrentEditing.addObject(indexPath)
}
I hope this help others. :)
I am working on a project where I have a table view which contains a number of cells with pretty complex content. It will be between usually not more than two, but in exceptions up to - lets say - 30 of them. Each of these complex cells contain a line chart. I am using ios-charts (https://github.com/danielgindi/ios-charts) for this.
This is what the View Controller's content looks like:
The code I use for dequeuing the cells in the viewController's cellForRowAtIndexPath method is kind of the following:
var cell = tableView.dequeueReusableCellWithIdentifier("PerfgraphCell", forIndexPath: indexPath) as? UITableViewCell
if cell == nil {
let nib:Array = NSBundle.mainBundle().loadNibNamed("PerfgraphCell", owner: self, options: nil)
cell = nib[0] as? FIBPerfgraphCell
}
cell.setupWithService(serviceObject, andPerfdataDatasourceId: indexPath.row - 1)
return cell!
and in the cell's code I have a method "setupWithService" which pulls the datasources from an already existing object "serviceObject" and inits the drawing of the graph, like this:
func setupWithService(service: ServiceObjectWithDetails, andPerfdataDatasourceId id: Int) {
let dataSource = service.perfdataDatasources[id]
let metadata = service.perfdataMetadataForDatasource(dataSource)
if metadata != nil {
if let lineChartData = service.perfdataDatasourcesLineChartData[dataSource] {
println("starting drawing for \(lineChartData.dataSets[0].yVals.count) values")
chartView.data = lineChartData
}
}
}
Now the problem: depending on how many values are to be drawn in the chart (between 100 and 2000) the drawing seems to get pretty complex. The user notices that when he scrolls down: as soon as a cell is to be dequeued that contains such a complex chart, the scrolling gets stuck for a short moment until the chart is initialized. That's of course ugly!
For such a case, does it make sense to NOT dequeue the cells on demand but predefine them and hold them in an array once the data that is needed for graphing is received by the view controller and just pull the corresponding cell out of this array when it's needed? Or is there a way to make the initialization of the chart asynchronous, so that the cell is there immediately but the chart appears whenever it's "ready"?
Thanks for your responses!
What you're trying to do is going to inevitably bump into some serious performance issues in one case or another. Storing all cells (and their data into memory) will quickly use up your application's available memory. On the other hand dequeueing and reloading will produce lags on some devices as you are experiencing right now. You'd be better off by rethinking your application's architecture, by either:
1- Precompute your graphs and export them as images. Loading images into and off cells will have much less of a performance knockoff.
2- Make the table view into a drill down menu where you only show one graph at a time.
Hope this helps!