images repeating cells when scrolled in tableview - ios

images are not showing properly in tableview , I have two Json Api (Primary/high) school. I can append the Both Json api Data and display into tableview,
tableview working fine it's showing both(primary/high) school data. when I can scroll the tableview images are jumping and images loading very slow in image view at tableview.
Before scrolling tableview its showing like this
After scrolling the tableview it's shows like this
after scrolling images are jumping,
this is the code
var kidsdata = [KidDetails]()
func getprimarydata(_firsturl: String,firstid:String,updatedate:String)
{
if errorCode == "0" {
if let kid_list = jsonData["students"] as? NSArray {
self.kidsdata.removeAll()
for i in 0 ..< kid_list.count {
if let kid = kid_list[i] as? NSDictionary {
let imageURL = url+"/images/" + String(describing: kid["photo"]!)
self.kidsdata.append(KidDetails(
name:kid["name"] as? String,
photo : (imageURL),
standard: ((kid["standard"] as? String)! + "std" + " " + (kid["section"] as? String)! + " section ")
))}}}}
}
func gethighdata(_secondurl:String ,secondid:String,updatedate:String)
{
if errorCode == "0" {
if let kid_list = jsonData["students"] as? NSArray {
for i in 0 ..< kid_list.count {
if let kid = kid_list[i] as? NSDictionary {
let imageURL = url+"/images/" + String(describing: kid["photo"]!)
self.kidsdata.append(KidDetails(
name:kid["name"] as? String,
photo : (imageURL),
standard: ((kid["standard"] as? String)! + "th" + " " + (kid["section"] as? String)! + " section ")
)
)
}
}
self.do_table_refresh()
}
}
}
func do_table_refresh()
{
DispatchQueue.main.async(execute: {
self.TableView.reloadData()
return
})
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell =
tableView.dequeueReusableCell(
withIdentifier: "cell", for: indexPath) as! DataTableViewCell
cell.selectionStyle = .none
cell.ProfileImage?.image = nil
let row = (indexPath as NSIndexPath).row
let kid = kidsdata[row] as KidDetails
cell.NameLabel.text = kid.name
cell.ProfileImage.image = UIImage(named: "profile_pic")
cell.ProfileImage.downloadImageFrom(link:kid.photo!, contentMode: UIViewContentMode.scaleAspectFill)
cell.ClassNameLabel.text = kid.standard
return cell
}
where I did mistake pls help me....!

AlamofireImage handles this very well. https://github.com/Alamofire/AlamofireImage
import AlamofireImage
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath) as! DataTableViewCell
cell.selectionStyle = .none
let kid = kidsdata[indexPath.row] as KidDetails
cell.NameLabel.text = kid.name
cell.ClassNameLabel.text = kid.standard
// assuming cell.ProfileImage is a UIImageView
cell.ProfileImage.image = nil
let frame = CGSize(width: 50, height: 50)
let filter = AspectScaledToFillSizeWithRoundedCornersFilter(size: frame, radius: 5.0)
cell.ProfileImage.af_setImage(withURL: urlToImage, placeholderImage: nil, filter: filter,
imageTransition: .crossDissolve(0.3), runImageTransitionIfCached: false)
return cell
}

All we need to do is use the prepareForReuse() function. As discussed in this medium article, This function is called before cell reuse, letting you cancel current requests and perform a reset.
override func prepareForReuse() {
super.prepareForReuse()
ProfileImage.image = nil
}

Related

Parsing multiple images in swift from JSON

Json has multiple images,
img1
Json has date with multiple images, I want show Date and first image of that Date in tableview, working fine.
img2
Note :
when click any cell in tableview, display that Date with all images in collection view, But am parsing only first image of that Date,that image only showing in collection view
how to parse all images from Json and pass to collection view from tableview, and display images into collocation view
img3
this is the code ...
json Code
if errorCode == "0" {
if let Media_list = jsonData["events"] as? [Any] {
self.Mediainfo.removeAll()
for i in 0 ..< Media_list.count {
if let MediaEventData = Media_list[i] as? [String: Any] {
var eventImages = MediaEventData["eventImages"] as? [[String: Any]]
if (eventImages?.count)! > 0 {
let bannerImage = eventImages?[0]["bannerImage"] as? String
print(bannerImage as Any)
self.imageUrl = self.url+"/images/events/" + String(describing: bannerImage!)
self.Mediainfo.append(MediaEvent(
eventId: MediaEventData["eventId"]as?String,
date: MediaEventData["date"]as?String,
eventname: MediaEventData["eventName"]as?String,
bannerImages: self.imageUrl
)
)
}
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "Media", for: indexPath)as! MediaCustomTableViewCell
let row = indexPath.row
let media = Mediainfo[row] as MediaEvent
cell.DisplayDate.text = media.date
cell.DisplayName.text = media.eventName
cell.selectionStyle = .none
cell.DisplayImage.downloadImageFrom(link:media.bannerImages, contentMode: UIViewContentMode.scaleAspectFit)
return cell
}
override func tableView(_ tableView: UITableView, heightForFooterInSection section: Int) -> CGFloat {
return CGFloat.leastNormalMagnitude
}
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath)
{
let media = Mediainfo[(indexPath.row)] as MediaEvent
let storyboard = UIStoryboard(name: "Main", bundle: nil)
let tabBarController = storyboard.instantiateViewController(withIdentifier: "IMAGEVID") as! UITabBarController
if let viewControllers = tabBarController.viewControllers,
let imageController = viewControllers.first as? ImagesCollectionViewController {
imageController.RecivedData1 = media.bannerImages
}
navigationController?.pushViewController(tabBarController, animated: true)
}
collection view Code :
override func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: reuseIdentifier, for: indexPath) as! ImageCollectionViewCell
cell.ImageviewCell.downloadImageFrom(link:nameofImages[indexPath.row], contentMode: UIViewContentMode.scaleAspectFit)
return cell
}
pls help me......!
u can do soemthing like this
let eventImages = MediaEventData["eventImages"] as? [[String: Any]]
if (eventImages?.count)! > 0 {
for i in 0...eventImages.count{
let bannerImage = eventImages?[i]["bannerImage"] as? String
self.imageUrl = self.url+"/images/events/" + String(describing: bannerImage!)
self.Mediainfo.append(bannerImage)
// or like u did u can append to array
self.Mediainfo.append(MediaEvent(
eventId: MediaEventData["eventId"]as?String,
date: MediaEventData["date"]as?String,
eventname: MediaEventData["eventName"]as?String,
bannerImages: self.imageUrl
)
} }
In didselect
let media = Mediainfo[(indexPath.row)] as MediaEvent
imageController.RecivedData1 = media.bannerImages
Your doing like this Means Your are slecting a particular cell and
that index your are passing to NextVC.
if you want to show all images You should pass complete array to
nextvc
You should declare a array of same type Mediainfo array in Next VC
and do like
EX: imageController.array = Mediainfo

Returns nil if I scroll tableView fast

Trying to load images in tableView asynchronously in (Xcode 9 and Swift 4) and seems I have a correct way but my code stops working if I scroll my tableView fast. So basically I had found nil error.
Here is my code:
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath) as! CustomTableViewCell
let feed = feeds[indexPath.row]
cell.titleLabel.text = feed.title
cell.pubDateLabel.text = feed.date
cell.thumbnailImageView.image = nil
if let image = cache.object(forKey: indexPath.row as AnyObject) as? UIImage {
cell.thumbnailImageView?.image = image
} else {
let imageStringURL = feed.imageUrl
guard let url = URL(string: imageStringURL) else { fatalError("there is no correct url") }
URLSession.shared.downloadTask(with: url, completionHandler: { (url, response, error) in
if let data = try? Data(contentsOf: url!) {
DispatchQueue.main.async(execute: {
guard let image = UIImage(data: data) else { fatalError("can't create image") }
let updateCell = tableView.cellForRow(at: indexPath) as! CustomTableViewCell // fast scroll issue line
updateCell.thumbnailImageView.image = image
self.cache.setObject(image, forKey: indexPath.row as AnyObject)
})
}
}).resume()
}
return cell
}
I have issue on the line:
let updateCell = tableView.cellForRow(at: indexPath) as! CustomTableViewCell
If I scroll down slowly everything works just fine and no mistakes appear.
Does anyone know where I've made a mistake?
This may happens if cell you are trying to get using tableView.cellForRow(at:) is not visible currently.
To avoid crash you can use optionals as:
let updateCell = tableView.cellForRow(at: indexPath) as? CustomTableViewCell // fast scroll issue line
updateCell?.thumbnailImageView.image = image
Keep everything as it is, I hope it should work without any errors.
You can consider one of popular UIImage extension libs, like I said in comment for example AlamofireImage and set thumbnail with the placeholder, as soon as image will be ready it will be replaced automatically.
One more thing I change no need to have updateCell I removed it.
Please add placeholder image and test it should work, sorry I didn't fully check syntax.
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath) as! CustomTableViewCell
let feed = feeds[indexPath.row]
if let image = cache.object(forKey: indexPath.row as AnyObject) as? UIImage {
cell.thumbnailImageView?.image = image
} else {
let imageStringURL = feed.imageUrl
guard let url = URL(string: imageStringURL) else { fatalError("there is no correct url") }
cell.thumbnailImageView.af_setImage(withURL : url, placeholderImage: <your_placeholderImage>)
return cell
}

How to display dynamically data from Server in CollectionViewCell in TableViewCell with swift3?

I got my json link data from TableViewCell , and then retrieve that data from server and display in collectionView with related TableViewCell data.
How to display this data in swift3? Please, help me.
I got url link (mainThemeList.main_associated_url,main_name) from TableViewCell.
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let mainThemeList = mainHomeThemeTable[(indexPath as NSIndexPath).row]
let cell = tableView.dequeueReusableCell(withIdentifier: "homecell") as! HomeCategoryRowCell
DispatchQueue.main.async {
cell.categoryTitle.text = mainThemeList.main_name
cell.mainAssociatedURL.text = mainThemeList.main_associated_url
self.prefs.set(mainThemeList.main_name, forKey: "main_name")
cell.categoryTitle.font = UIFont.boldSystemFont(ofSize: 17.0)
cell.collectionView.reloadData()
}
DispatchQueue.main.async {
self.retrieveDataFromServer(associated_url: mainThemeList.main_associated_url,main_name: mainThemeList.main_name)
}
return cell
}
And then data related url link data from Server.
private func retrieveDataFromServe(associated_url : String , main_name: String) {
SwiftLoading().showLoading()
if Reachability().isInternetAvailable() == true {
self.rest.auth(auth: prefs.value(forKey: "access_token") as! String!)
rest.get(url: StringResource().mainURL + associated_url , parma: [ "show_min": "true" ], finished: {(result : NSDictionary, status : Int) -> Void in
self.assetsTable.removeAll()
if(status == 200){
let data = result["data"] as! NSArray
if (data.count>0){
for item in 0...(data.count) - 1 {
let themes : AnyObject = data[item] as AnyObject
let created = themes["created"] as! String
let assets_id = themes["id"] as! Int
let name = themes["name"] as! String
var poster_img_url = themes["poster_image_url"] as! String
let provider_id = themes["provider_id"] as! Int
poster_img_url = StringResource().posterURL + poster_img_url
self.assetsTable.append(AssetsTableItem(main_name: main_name,created: created,assets_id: assets_id, name: name, poster_image_url: poster_img_url,provider_id: provider_id))
}
}
SwiftLoading().hideLoading()
}else{
SwiftLoading().hideLoading()
}
})
}
}
Retrieve data from Server data store in assetsTable.
And then assetsTable data display in CollectionViewCell.
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "videoCell", for: indexPath) as! HomeVideoCell
cell.movieTitle.text = list.name
cell.imageView.image = list.image
return cell
}
My problem is collectionViewCell data are duplicate with previous assetsTable data and didn't show correct data in CollectionView.
My tableViewCell show (Action, Drama) label and My CollectionViewCell show movies Name and Movie Image. I retrieve data for CollectionViewCell from server but CollectionViewCell didn't display related data.
in HomeVideoCell Subclass clean up data in prepareforreuse
override func prepareForReuse() {
super.prepareForReuse()
self.movieTitle.text = ""
self.imageView.image = nil
}

UIImage overlaps labels if it's set to .scaleAspectFill

My app loads images from a backend and displays them in a UITableViewCell, that contains a UIImageView to display it and some labels and buttons.
I've added the suggested contraints to the UITableViewCell with the 'Reset to suggested contraints' option.
Here's some of the code after retrieving the data:
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
var cell = PostTableViewCell()
if (self.posts.count == 0) { return cell }
let post = posts[indexPath.row]
// Instancia o reuse identifier
if post["post_image"] != nil {
cell = tableView.dequeueReusableCell(withIdentifier: Storyboard.PostWithImage, for: indexPath) as! PostTableViewCell
} else {
cell = tableView.dequeueReusableCell(withIdentifier: Storyboard.PostWithoutImage, for: indexPath) as! PostTableViewCell
}
return cell
}
override func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
var cell = PostTableViewCell()
cell = tableView.dequeueReusableCell(withIdentifier: Storyboard.PostWithImage) as! PostTableViewCell
return cell.bounds.size.height;
}
override func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
var cell = PostTableViewCell()
cell = tableView.dequeueReusableCell(withIdentifier: Storyboard.PostWithImage) as! PostTableViewCell
return cell.bounds.size.height;
}
private func configureCell(cell: PostTableViewCell, atIndexPath indexPath: IndexPath) {
cell.queue.cancelAllOperations()
let operation: BlockOperation = BlockOperation()
operation.addExecutionBlock { [weak operation] () -> Void in
DispatchQueue.main.sync(execute: { [weak operation] () -> Void in
if (operation?.isCancelled)! { return }
let post = self.posts[indexPath.row]
cell.accessibilityIdentifier = post.recordID.recordName
guard let postTitle = post["post_title"], let postBody = post["post_body"] else {
return
}
if let asset = post["post_image"] as? CKAsset {
self.imageCache.queryDiskCache(forKey: post.recordID.recordName, done: { (image, cachetype) in
if image != nil {
cell.postImageView.contentMode = .scaleAspectFill
cell.postImageView.autoresizingMask = [.flexibleBottomMargin,
.flexibleHeight,
.flexibleLeftMargin,
.flexibleRightMargin,
.flexibleTopMargin,
.flexibleWidth ];
cell.postImageView.image = image!
} else {
do {
let data = try Data(contentsOf: asset.fileURL)
let image = UIImage(data: data)
cell.postImageView.contentMode = .scaleAspectFill
cell.postImageView.autoresizingMask = [.flexibleBottomMargin,
.flexibleHeight,
.flexibleLeftMargin,
.flexibleRightMargin,
.flexibleTopMargin,
.flexibleWidth ];
cell.postImageView.image = image!
self.imageCache.store(image!, forKey: post.recordID.recordName)
} catch {
print("Error 1001 = \(error.localizedDescription)")
}
}
})
}
cell.titleLabel.text = postTitle as? String
cell.bodyLabel.text = postBody as? String
})
}
cell.queue.addOperation(operation)
}
Here's some prints from the app itself that shows the image overlapping over the labels.
It only overlaps if the image is in portrait mode, if the image was taken in landscape it suits well.
What's the best way to bypass this issue?
You can programmatically tell the image to draw only in the given image area. If your constraints are working properly and it is staying the correct size, the image may just be drawing beyond the View bounds because of the .scaleAscpedtFill setting.
Do this by using .clipToBounds = true.
cell.postImageView.clipToBounds = true
Or, you can set it in interface builder as well, per the image below.
Give that a try and see if that helps?

tableView jumping scrolling after reloadData

My tableView scrolling is jumping when I reload tableView with new data. Here is the code for cellForRowAtIndexPath:
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let section = indexPath.section
let index = indexPath.row
let info = data[sections[section]]![index] as ConversationMessage
if info.from == .Me {
var cell: ConversationDialogMeTableCell = tableView.dequeueReusableCellWithIdentifier("meCell", forIndexPath: indexPath) as! ConversationDialogMeTableCell
cell.backgroundColor = UIColor.clearColor()
cell.selectionStyle = .None
cell.messageLabel.text = info.text
return cell
} else if info.from == .Other {
var cell: ConversationDialogOtherTableCell = tableView.dequeueReusableCellWithIdentifier("otherCell", forIndexPath: indexPath) as! ConversationDialogOtherTableCell
cell.backgroundColor = UIColor.clearColor()
cell.selectionStyle = .None
cell.personName.textColor = UIColor(hex: 0x6d6d6d)
cell.messageContainerView.backgroundColor = UIColor(hex: 0x6d6d6d)
cell.messageContainerView.layer.cornerRadius = 5
cell.messageContainerView.clipsToBounds = true
Alamofire.request(.GET, info.personImage).response {
(request, response, data, error) in
let image = UIImage(data: data!, scale: 1)!
cell.personImage.image = image
cell.personImage.contentMode = UIViewContentMode.ScaleAspectFill
cell.personImage.layer.cornerRadius = cell.personImage.frame.height / 2
cell.personImage.clipsToBounds = true
}
cell.personName.text = info.personName
cell.personMessage.text = info.text
return cell
}
return UITableViewCell()
}
For the first load scrolling is smooth, but if I will add new data in my tableView and call reloadData() the scrolling is jumping when new cells are shown.
Here is the code where I insert new data to my model:
func client(client: PubNub!, didReceiveMessage message: PNMessageResult!) {
if message.data.subscribedChannel == self.channel {
if let messageInfo: AnyObject = message.data.message {
let date = (messageInfo["date"] as! String).getDateString()
let messageText = messageInfo["message"] as! String
let from: ConversationMessage.sendFromType = (messageInfo["userID"] as! String) == self.userID ? .Me : .Other
let image = messageInfo["userPhoto"] as! String
let name = messageInfo["userName"] as! String
if data[date] != nil {
data[date]!.append(ConversationMessage(text: messageText, from: from, personImage: image, personName: name, date: messageInfo["date"] as! String))
} else {
data[date] = [ConversationMessage(text: messageText, from: from, personImage: image, personName: name, date: messageInfo["date"] as! String)]
}
for section in self.sections {
self.data[section]! = sorted(self.data[section]!) { Utils.compareDateTime($0.date, with: $1.date, order: .OrderedAscending) }
}
tableView.reloadData()
tableViewScrollToBottom(false)
}
}
}
Maybe it happens because of function to scroll tableView to bottom:
func tableViewScrollToBottom(animated: Bool) {
let delay = 0.1 * Double(NSEC_PER_SEC)
let time = dispatch_time(DISPATCH_TIME_NOW, Int64(delay))
dispatch_after(time, dispatch_get_main_queue(), {
let numberOfSections = self.tableView.numberOfSections()
let numberOfRows = self.tableView.numberOfRowsInSection(numberOfSections - 1)
if numberOfRows > 0 {
let indexPath = NSIndexPath(forRow: numberOfRows - 1, inSection: (numberOfSections - 1))
self.tableView.scrollToRowAtIndexPath(indexPath, atScrollPosition: UITableViewScrollPosition.Bottom, animated: animated)
}
})
}
One more thing. Should I cache uploaded images? Maybe this is causing jumping scroll. Can someone help me to solve my issue?
Do not return UITableViewAutomaticDimension from
-(CGFloat)tableView:(UITableView *)tableView estimatedHeightForRowAtIndexPath:(NSIndexPath *)indexPath;
There may be two possible solutions -
Either you should return max height for your cell.
OR you may cache the cell.bounds.size.height from
tableView:willDisplayCell:forRowAtIndexPath: and return same value in estimatedHeightForRowAtIndexPath

Resources