UIWebImage+ AFNetworking images shifting in cells - ios

I have a collection view. In the cellForRow method I set an object in my collectionViewCell. The setter for that object takes the object's image url and downloads the image asynchroneously using AFNetworking. (the setter is in the custom cell subclass )
However when I download new images and i reloadData, I have to scroll down for the proper images to load... And sometimes the images change cells or duplicate (but I know the object in that cell doesn't change because the object title is the expected one.
What is happening?

If you want the image to swap out without reloading the cell (or scrolling down) you will need to call:
[self.imageView setImageWithURL:<#some url#> placeholderImage:<#placeholder image same size as imageview#>];
AFNetworking takes care of caching images so you can be safe to call the same setter every time cellForRow is called (to avoid image reuse on different cells)
NB: Its important the placeholder image is the same size as the imageView - your image will be swapped out.

I think this could be mainly because of the cell being reused bu the collectionview. Try setting the image property of your custom cell to nil right after dequeueReusableCellWithReuseIdentifier:

Related

Name Label overlapping each time it is loaded

Our app has a social feed with a name label similar to Facebook with a FeedController and FeedCell class. Each time we scroll back to a previously loaded cell, it reloads, so the name label becomes darker, the text becomes bolder and starts to overlap. How do we fix this? We tried the prepareToReuse method and setting the cell's label to nil, but that did not help. Any help would be greatly appreciated!
It appears that you're regenerating the label and adding it to your cell's content view every time that the label is reused.
Inside your FeedCell class, make sure to only initiate your interface elements in your initializer. From there, you can fill your cell with data in the cellForRowAtIndexPath: method of your UITableViewDataSource.
Inside cellForRowAtIndexPath:, make sure to not add any views to the cell as this could contribute to the issue you're describing. As a rule of thumb, I make sure to initialize the views in the cell subclass's initializer, and only manipulate properties of these views (like hidden, alpha, etc) when working with the cells.
Moving forward, you can use prepareForReuse to clear any data from your cell that may be leftover from the previous time the cell was used. In many cases though, this isn't necessary as the data will be changed in cellForRowAtIndexPath:.

adding subview in a single uitableviewcell

Im facing a problem with adding a UIImageView to a single UITableViewCell. I add the subview like this in the cellForIndexPath delegate method which is ONLY added to the cell if the self.mediaTypeArray contains the string: "Image" at the index: indexPath.row
let cell = self.timelineTableView.dequeueReusableCellWithIdentifier( NSStringFromClass(ClassicCaseCell), forIndexPath: indexPath) as? ClassicCaseCell
if self.mediaTypeArray[indexPath.row] == "Image" {
let imageView = UIImageView()
imageView.frame.size = (cell?.evidenceView.frame.size)!
imageView.frame.origin = CGPointZero
imageView.image = img
cell?.evidenceView.addSubview(imageView)
}
Which it works great however, I find that every other two cells contains that same imageView even when self.mediaTypeArray[indexPath.row] is NOT equal to "Image" and I don't understand why. I think it may have something to do with reusable tableviewcells but I still don't see why it would do this. Please help!
I'm getting the feeling that this is because of cells being re-used.
A way you can work around this is to override your ClassicCaseCell's prepareForReuse method to remove any image view from its evidenceView.
I would however recommend that you don't add the image view in this fashion (through the delegate's cellForIndexPath method). Instead, your ClassicCaseCell should hold the image view as an instance variable which you can then set in cellForIndexPath. This way, there is only at most one. You can also make sure to set the image view to be nil in prepareForReuse, making sure that it won't appear in the cell if it is not set.
First, don't use tag property as recommended elsewhere. That was a technique used a long time ago, but Apple discourages that practice now. Second, I'd suggest you simplify your life and simply don't programmatically add image views in cellForRowAtIndexPath. If you programmatically add image views, cell reuse introduces a clumsy process of determining whether (a) you need an image view; (b) whether there is an existing image view; and (c) possibly adding/removing image view and/or getting reference to existing one.
One very simple solution is to just have two cell prototypes, one with an image view and another without. Then, based upon the media type, dequeue a cell with the appropriate storyboard identifier and use it.
The other alternative is to have the image view in the cell regardless, and hide/show it as appropriate. The challenge then becomes how to best manage two sets of the constraints, one for when the image view is visible and one when it's not. You can do this with judicious choice of constraint priorities, activating/deactivating the appropriate constraints in cellForRowAtIndexPath, etc. It can be done, but this is more cumbersome than the above approach, whereby you just employ two cell prototypes.
You only need to add the UIImageView once so if the cell is re-used again, it (might) already be there. Your problem is to detect if you've already added it or not. Here are a couple suggestions:
1) ALWAYS create it (and just don't set the image, or hide it)
2) assign it a unique tag and look for the tag when you need to set it... no tag, then create it
Override prepareForReuse delegation in your tableview cell and remove imageview from there

Self Sizing Cells With Asynchronous ImageLoading

Update: This Github link contains the project. If possible download and tap on Reload on top you'll get to know the difference. and Mr. Zhang thank you for "Aspect Scale to Fill" suggestion. it helped me little.
I've a tableview which loads images Asynchronously (with AFNetworking UIImageView Category Class).Images are compressing for first time on visible cells. Once I reload again or scroll op and down Images are adjusting according to its size.
Basically I'll get different size Images. Which width should be cell width, height can be anything
Implemented all necessary steps for selfsizing(proper autolayout constraints and proper delegate methods)
//my tableview setup
self.tblTest?.estimatedRowHeight = 1000.0 //i've tried with all possible guesses and
//tried with delegate also
self.tblTest?.rowHeight = UITableViewAutomaticDimension
I've added constraints as below:
in my test cell.
func setUpImage(url:NSURL){
//tried with another function also without NSURLRequest
self.imvTest?.setImageWithURLRequest(NSURLRequest(URL: url),
placeholderImage: UIImage(named: "store_placeholder"),
success: { (requset, response, image) -> Void in
self.imvTest?.image = image
print(image.size)
}, failure: { (error) -> Void in
self.imvTest?.image = nil
})
}
Result
Expected
How can i prevent image squeezing for the first time??
P.S: I don't think its correct to reload table view each and time image is being set.
Please suggest me what i've been missing and any content priorities etc.,??
Try calling
tableView.beginUpdates()
tableView.endUpdates()
after setting the image in the success closure
Or try tableView.reloadRowsAtIndexPaths with the indexPath of the cell after setting the image
What I believe is happening is that the cell gets laid out with its original content size. Then the new image asynchronously comes in and gets set. Typically you set the data for the cell in cellForRowAtIndexPath:, which occurs before cell layout. However when an image comes in asynchronously, layout has already happened, so it's too late.
When a new image comes in, the data has changed, so you need to tell the tableview to reload the data.
Instead of reloading the tableview as a whole however, you can reload an individual cell when the image comes in. This will of course be much more performant than reloading the entire tableview.

NSURLConnection delay leads to an empty UItableViewCell without the picture

My app downloads the user's Facebook profile picture with an asynchronous (NSURLConnection) connection so that it can display the profile picture on a customized UITableViewCell. The problem is; the customized tableViewCell is created before the picture gets downloaded so the delay leads to an empty tableViewCell without the picture. How can I solve this problem?
My approach is to reach each cell by using a (for-in enumeration) and (a tag for each cell) in "connectionDidFinishLoading" method.
So guys, what do you think about my approach and do you have any better approaches???
Thanks for your help,
E.
Trying to tag and loop through your cells to find matches won't work because of UITableViewCell reuse. There are only as many cells in memory as you can see on screen, and these cells get recycled to display different data. Therefore, you won't be able to create a tag for each row in your table view, because the table view is only using a handful of cells.
What you should do instead is create a UITableViewCell subclass that knows how to asynchronously download and display in the image itself. Using the UIImageView category from AFNetworking is perfect for doing something like this, instead of having to manage the URL connection yourself. Import this category in your cell subclass, and write a method that calls setImageWithURL: to asynchronously download and display the image. Also, make sure to overload the UITableViewCell method prepareForReuse, in which you should call cancelImageRequestOperation on your image view. This is so the request to download the image is cancelled if the cell is reused before the download is complete.

UITableViewCell load Images

I have 16 locally stored pre-rendered 40x40 px images that I want to use as my UITableViewCell images. I can get it to display them fine using [UIImage imageNamed:]; but I have noticed this slows down the table view scrolling.
I have looked through the apple example for lazy loading etc. and understand I need to do it on a background thread or asynchronously, but have not found an example for local images.
Can anybody help?
Subclass the UITableView cell, and create a new method in the cell that is something like:
- (void)setImage:(NSString *)imageName;
Then from where you used to set the image, change it to instead do something like:
[cell setImage:nil];
[cell performSelector:#selector(setImage:) withObject:#"imageName" afterDelay:0];
Changing it to performSelector:withObject:afterDelay: means that the code to set the image will not execute while the tableView is scrolling. This should lead to a significant improvement in scroll performance as it will not set images into cells until the scrolling stops.
However you will notice the lack of images while scrolling so you may want to consider a small placeholder image in the images place to appear while scrolling.
Personally I use this method conditionally in my code. I detect how old the UIDevice is, and if its an older generation device I will lazy load like this to increase scroll performance.

Resources