Welcome to the Treehouse Community
Want to collaborate on code errors? Have bugs you need feedback on? Looking for an extra set of eyes on your latest project? Get support with fellow developers, designers, and programmers of all backgrounds and skill levels here with the Treehouse Community! While you're at it, check out some resources Treehouse students have shared here.
Looking to learn something new?
Treehouse offers a seven day free trial for new students. Get access to thousands of hours of content and join thousands of Treehouse students and alumni in the community today.
Start your free trialjean-marie castellucci
4,954 PointsRibbit/Swift clone : Reusable UITableViewCells change after I scroll
I am facing a problem when using reusable UITableViewCells. For a split second before the cell updates it shows the wrong info. Like in instagram i have an avatar picture for the user who posted the photo. When the tableView is first loaded, no probleme, the avatar is the good one. If i scroll down, there are others posts with other avatars, and when i scroll up, for a split second before the cell updates it shows the wrongs avatars (from the lower cells...) Does anyone know the best practice to deal with that? In instagram we can see that avatars user are placed whithin a custom section so that the photo scroll under the section and if the scroll continue, the section is passed to another, anyone know how to do that ?
This is my code
import UIKit
import QuartzCore
class WallTableViewController: UITableViewController, UINavigationControllerDelegate {
@IBOutlet var posterAvatar: UIImageView!
override func preferredStatusBarStyle() -> UIStatusBarStyle {
return UIStatusBarStyle.LightContent
}
var timeLineData:NSMutableArray = NSMutableArray ()
var followedFriends:NSMutableArray = NSMutableArray ()
func loadUser () {
followedFriends.removeAllObjects()
var friendsRelation: AnyObject! = PFUser.currentUser().objectForKey("KfriendsRelation")
var findUser : PFQuery = friendsRelation.query()
findUser.findObjectsInBackgroundWithBlock { (objects:[AnyObject]!, error:NSError!) -> Void in
if !(error != nil) {
// The find succeeded.
println("succesfull load Users")
// Do something with the found objects
for object in objects {
self.followedFriends.addObject(object)
println("users added to userlist")
for item in self.followedFriends {
println(item) }
}
self.tableView.reloadData()
} else {
// Log details of the failure
println("error loadind user ")
}
}
}
func loadPost () {
timeLineData.removeAllObjects()
let currentUser = PFUser.currentUser()
var findPost:PFQuery = PFQuery(className: "UserPost")
//query for the friends of the user
var friendsRelation: AnyObject! = PFUser.currentUser().objectForKey("KfriendsRelation")
var findFriends : PFQuery = friendsRelation.query()
//using the friends from the query above, we find all the posts of the friends of the current user
var findPosts:PFQuery = PFQuery(className: "UserPost")
findPosts.whereKey("from", matchesQuery:findFriends)
findPost.orderByDescending("createdAt")
//run the query
findPosts.findObjectsInBackgroundWithBlock { (objects:[AnyObject]!, error:NSError!) -> Void in
if !(error != nil) {
//found posts
for object in objects {
self.timeLineData.addObject(object)
}
self.tableView.reloadData()
} else {
// Log details of the failure
println("error loadind posts ")
}
}
}
override func numberOfSectionsInTableView(tableView: UITableView) -> Int {
return 1
}
override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return timeLineData.count
}
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell:WallTableViewCell = tableView.dequeueReusableCellWithIdentifier("cell", forIndexPath: indexPath) as WallTableViewCell
let userPost:PFObject = self.timeLineData.objectAtIndex(indexPath.row) as PFObject
//define the username
var findUser:PFQuery = PFUser.query()
findUser.whereKey("objectId", equalTo: userPost.objectForKey("from").objectId)
findUser.findObjectsInBackgroundWithBlock{
(objects:[AnyObject]!, error:NSError!) -> Void in
if error == nil {
if let user:PFUser = (objects as NSArray).lastObject as? PFUser {
cell.usernameLabel.text = user.username
// define avatar poster
if let avatarImage:PFFile = user["profileImage"] as? PFFile {
avatarImage.getDataInBackgroundWithBlock{(imageData:NSData!, error:NSError!)-> Void in
if !(error != nil) {
let image:UIImage = UIImage(data: imageData)
cell.posterAvatar.image = image as UIImage
cell.posterAvatar.layer.cornerRadius = 24
cell.posterAvatar.clipsToBounds = true
}
}
}
else {
cell.posterAvatar.image = UIImage(named: "Avatar-1")
cell.posterAvatar.layer.cornerRadius = 24
cell.posterAvatar.clipsToBounds = true
}
}
}
}
//define the imagepost
let imagesPost:PFFile = userPost["imageFile"] as PFFile
imagesPost.getDataInBackgroundWithBlock{(imageData:NSData!, error:NSError!)-> Void in
if !(error != nil) {
let image:UIImage = UIImage(data: imageData)
cell.imagePosted.image = image as UIImage
}
else {
println("error")
}
}
return cell
}
override func viewDidAppear(animated: Bool) {
var currentUser = PFUser.currentUser()
if (currentUser != nil) {
println("User allready logued")
}
else {
// Show the signup or login screen
self.performSegueWithIdentifier("goToLogIn", sender: self)
}
}
override func viewDidLoad() {
super.viewDidLoad()
}
override func viewWillAppear(animated: Bool) {
self.tableView.separatorColor = UIColor.whiteColor()
tabBarController?.tabBar.tintColor = UIColor.whiteColor()
self.loadUser()
self.loadPost()
}
}
3 Answers
jean-marie castellucci
4,954 PointsOMG i've found a quickest solution thanks to Parse !
i just added this to my query :
myquery.cachePolicy = kPFCachePolicyCacheElseNetwork
And now it work perfectly.
The things that i don't know is if a particular user change his avatars photo, how do the cache will know there is something knew ?
Stone Preston
42,016 Pointsyou need to cache the photos after you download them. Whenever you set up the cell in cellForRowAtIndexPath, you first check to see if the photo exists in your cache, if it does you dont download it you just load it from the cache instantly. If it is not in the cache, that means you have not downloaded it, so you download it from your backend, then cache it for next time.
there may be a few 3rd party swift libraries for quick and easy caching, a quick search found this one. looks simple and easy to use.
jean-marie castellucci
4,954 PointsThanks Stone, isn't this one for caching NSString object only ?i ll try but i think i' m too new in dev for using this caching method. I m gona look if i find a tuto for that specific task.