Uitableviewcell Shows Incorrect Results from Document Folder

UITableViewCell shows incorrect results from document folder

 var superArray = [String]()
var filterArray = [String]()
func filter() {
var proString: String!
for proItem in mp3Files {
var proFolder = fileManager.URLsForDirectory(NSSearchPathDirectory.DocumentDirectory, inDomains: NSSearchPathDomainMask.UserDomainMask)
var americaURL: NSURL!
if var proURL: NSURL = proFolder.first as? NSURL {
americaURL = proURL.URLByAppendingPathComponent(proItem)
}
var proPlayerItem = AVPlayerItem(URL: americaURL)
var proData = proPlayerItem.asset.commonMetadata as! [AVMetadataItem]
for proFiles in proData {
if proFiles.commonKey == "artist" {
superArray.append(proFiles.stringValue)
}
}
}
filterArray = Array(Set(superArray))
filterArray.sort(){ $0 < $1 }
}

// MARK: - Table view data source

override func numberOfSectionsInTableView(tableView: UITableView) -> Int {
// #warning Potentially incomplete method implementation.
// Return the number of sections.
return 1 ?? 0
}

override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
// #warning Incomplete method implementation.
// Return the number of rows in the section.
return filterArray.count ?? 0
}

var name: String!
var nameArtist: String!

//
var cellStrings: String!
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("cell", forIndexPath: indexPath) as! UITableViewCell

nameArtist = filterArray[indexPath.row]

cell.textLabel?.text = nameArtist

return cell
}

UITableViewCell has duplicates from document folder

I solved my problem

var superArray = [String]()
var filterArray = [String]()
func filter() {
var proString: String!
for proItem in mp3Files {
var proFolder = fileManager.URLsForDirectory(NSSearchPathDirectory.DocumentDirectory, inDomains: NSSearchPathDomainMask.UserDomainMask)
var americaURL: NSURL!
if var proURL: NSURL = proFolder.first as? NSURL {
americaURL = proURL.URLByAppendingPathComponent(proItem)
}
var proPlayerItem = AVPlayerItem(URL: americaURL)
var proData = proPlayerItem.asset.commonMetadata as! [AVMetadataItem]
for proFiles in proData {
if proFiles.commonKey == "artist" {
superArray.append(proFiles.stringValue)
}
}
}
filterArray = Array(Set(superArray))
filterArray.sort(){ $0 < $1 }
}

Custom UITableViewCell showing incorrect values

So the problem turned out to be a lack of calling setNeedsDisplay() in my CircleView class. Thanks William GP.

UITableViewCell image always showing the last cell image

So at issue here is the loop inside of cell at index path. This function is called once for every row returned by the rows in section function. So you should almost never need a loop in this function. Try something like the following.

func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "Cell")
let findPath = NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true)
let card = allCards[indexPath.row]
cell?.textLabel?.text = card.name
let savedFile = (findPath[0] + "/" + card.cardID + ".png")
print(savedFile)
let image = UIImage(contentsOfFile: savedFile)
cell?.imageView?.image = image
return cell!
}

UITableViewCell shows the wrong image while images load

UITableView only uses a handful of cells (~ the max number of visible cells on screen) when displaying a collection of items, so you'll have more items than cells. This works because of the table view reusing mechanism, which means that the same UITableViewCell instance will be used for displaying different items. The reason why you are having problems with the images is because you aren't handling the cell reusing properly.

In the cellForRowAt function you call:

cell.postHeroImage.loadImageUsingCacheWithUrlString(postImageURL)

While you scroll the table view, in different invocations of cellForRowAt this function will be called for the same cell, but (most probably) displaying the content of different items (because of the cell reusing).

Let's X be the cell you are reusing, then these are roughly the functions that will be called:

1. X.prepareForReuse()
// inside cellForRowAt
2. X.postHeroImage.loadImageUsingCacheWithUrlString(imageA)

// at this point the cell is configured for displaying the content for imageA
// and later you reuse it for displaying the content of imageB
3. X.prepareForReuse()
// inside cellForRowAt
4. X.postHeroImage.loadImageUsingCacheWithUrlString(imageB)

When the images are cached, then you will always have 1, 2, 3 and 4 in that order, that's why you don't see any issues in that case. However, the code that downloads an image and set it to the image view runs in a separate thread, so that order isn't guaranteed anymore. Instead of only the four steps above, you will have something like:

1. X.prepareForReuse()
// inside cellForRowAt
2. X.postHeroImage.loadImageUsingCacheWithUrlString(imageA)
// after download finishes
2.1 X.imageView.image = downloadedImage

// at this point the cell is configured for displaying the content for imageA
// and later you reuse it for displaying the content of imageB
3. X.prepareForReuse()
// inside cellForRowAt
4. X.postHeroImage.loadImageUsingCacheWithUrlString(imageB)
4.1 X.imageView.image = downloadedImage

In this case, because of concurrency, you could end up with the following cases:

  • 1, 2, 2.1, 3, 4, 4.1: Everything is displayed properly (this will happen if you scroll slowly)
  • 1, 2, 3, 2.1, 4, 4.1: In this case the first image finishes downloading after the call to reuse the cell finishes, so the old image will be displayed (wrongly) for a short period of time while the new one is downloaded, and then replaced.
  • 1, 2, 3, 4, 2.1, 4.1: Similar to the case above.
  • 1, 2, 3, 4, 4.1, 2.1: In this case the old image finishes downloading after the new one (there is no guaranty the downloads finish in the same order they started) so you will end up with the wrong image. This is the worst case.

For fixing this problem, let's turn our attention to the problematic piece of code inside the loadImageUsingCacheWithUrlString function:

let url = URL(string: urlString)
URLSession.shared.dataTask(with: url!, completionHandler: { (data, response, error) in
DispatchQueue.main.async(execute: {
if let downloadedImage = UIImage(data: data!) {
imageCache.setObject(downloadedImage, forKey: urlString as NSString)
// this is the line corresponding to 2.1 and 4.1 above
self.image = downloadedImage
}
})

}).resume()

As you can see, you are setting self.image = downloadedImage even when you aren't displayed the content associated to that image anymore, so what you need is some way to check if that's still the case. Since you define loadImageUsingCacheWithUrlString in an extension for UIImageView, then you don't have much context there to know whether you should display the image or not. Instead of that, I propose to move that function to an extension of UIImage that will return that image in a completion handler, and then call that function from inside your cell. It would look like:

extension UIImage {
static func loadImageUsingCacheWithUrlString(_ urlString: String, completion: @escaping (UIImage) -> Void) {
if let cachedImage = imageCache.object(forKey: urlString as NSString) as? UIImage {
completion(cachedImage)
}

//No cache, so create new one and set image
let url = URL(string: urlString)
URLSession.shared.dataTask(with: url!, completionHandler: { (data, response, error) in
if let error = error {
print(error)
return
}

DispatchQueue.main.async(execute: {
if let downloadedImage = UIImage(data: data!) {
imageCache.setObject(downloadedImage, forKey: urlString as NSString)
completion(downloadedImage)
}
})

}).resume()
}
}

class FeedItem: UITableViewCell {
// some other definitions here...
var postImageURL: String? {
didSet {
if let url = postImageURL {
self.image = UIImage(named: "loading")

UIImage.loadImageUsingCacheWithUrlString(url) { image in
// set the image only when we are still displaying the content for the image we finished downloading
if url == postImageURL {
self.imageView.image = image
}
}
}
else {
self.imageView.image = nil
}
}
}
}

// inside cellForRowAt
cell.postImageURL = postImageURL

Swift 4 Table View Getting Wrong Cell

Cells are being reused - you can only get reference to the visible cells.

let myIndexPath = IndexPath(row: 4 ,section: 0)
let cell = MyTableView.cellForRow(at: myIndexPath)
cell?.backgroundColor = UIColor.yellow

cell in your case is nil when row number 4 isn't visible. If you wanna change behaviour in the cells you should modify the model and call for example reloadData on your UITableView.

UItableview Cell changes data and attributes randomly or while scrolling

I've had this issue before, because TableViewCells are re-used you need to ensure you set the background regardless of if it is default or not.

So when you are adding in the code to set the background to green, add an else statement or before the query set the cell background to white/your default color Issue with UITableViewCells Repeating Content



Related Topics



Leave a reply



Submit