I have an app like instagram that display photos in a tableView.
When the network is slow, image are re used in wrong cells and my dowload indicator label is also reused in wrong cells as i scroll fast.
I tried to use async image loading but can't optimize it.
Here is my cellForRowAtIndexPath method :
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell:WallTableViewCell = tableView.dequeueReusableCellWithIdentifier("cell", forIndexPath: indexPath) as WallTableViewCell
if indexPath.section == timeLineData.count - 1 {
println("load more pics")
loadPost()
}
cell.tag = indexPath.row
// timeLineData is my data array
if timeLineData.count != 0 {
let userPost = timeLineData.objectAtIndex(indexPath.section) as PFObject
cell.commentButton.tag = indexPath.section
// check if image is in the cache
if let imagePostedCache: AnyObject = self.imageCache.objectForKey(userPost.objectId){
dispatch_async(dispatch_get_main_queue(), {
if let cellToUpdate = tableView.cellForRowAtIndexPath(indexPath) as? WallTableViewCell {
cell.imagePosted.image = imagePostedCache as? UIImage
cell.downloadProgressLabel.hidden = true
}
})
}
// if it is not in the cache get the image from Parse
else if let imagesPost:PFFile = userPost["imageFile"] as? PFFile {
cell.imagePosted.image = nil
cell.downloadProgressLabel.hidden = false
imagesPost.getDataInBackgroundWithBlock({ (imageData:NSData!, error :NSError!) -> Void in
if !(error != nil) {
let image:UIImage = UIImage(data: imageData)!
// add image to the cache
self.imageCache.setObject( image , forKey: userPost.objectId)
// display image in the cell
dispatch_async(dispatch_get_main_queue(), {
if let cellToUpdate = tableView.cellForRowAtIndexPath(indexPath) as? WallTableViewCell {
cell.imagePosted.image = image as UIImage
}
})
}
else {
println("error")
}
}, progressBlock: { (progressStatus :Int32) -> Void in
cell.downloadProgressLabel.text = "\(progressStatus) %"
if progressStatus == 100 {
cell.downloadProgressLabel.text = ""
}
})
}
// Define description
if cell.tag == indexPath.row {
cell.brandLabel.text = userPost["photoText"] as? String
}
}
return cell
}
Here is my custom cell :
import UIKit
import QuartzCore
class WallTableViewCell: UITableViewCell {
#IBOutlet var downloadProgressLabel: UILabel!
#IBOutlet var commentButton: UIButton!
#IBOutlet var imagePosted: UIImageView!
#IBOutlet var brandLabel: UILabel!
}
WallTableViewCell
import UIKit
import QuartzCore
class WallTableViewCell: UITableViewCell
{
var isDownloadingInProgress
#IBOutlet var downloadProgressLabel: UILabel!
#IBOutlet var commentButton: UIButton!
#IBOutlet var imagePosted: UIImageView!
#IBOutlet var brandLabel: UILabel!
func updateCellWithUserPost(userPost: PFObject)
{
if let imagePostedCache: AnyObject = self.imageCache.objectForKey(userPost.objectId)
{
self.imagePosted.image = imagePostedCache as? UIImage
self.downloadProgressLabel.hidden = true
}
else if let imagesPost:PFFile = userPost["imageFile"] as? PFFile
{
self.imagePosted.image = nil
self.downloadProgressLabel.hidden = false
isDownloadingInProgress = true
imagesPost.getDataInBackgroundWithBlock({ (imageData:NSData!, error :NSError!) -> Void in
isDownloadingInProgress = false
if !(error != nil)
{
let image:UIImage = UIImage(data: imageData)!
self.imageCache.setObject( image , forKey: userPost.objectId)
self.imagePosted.image = image as UIImage
}
else
{
println("Error while downloading image")
}
}, progressBlock: { (progressStatus :Int32) -> Void in
self.downloadProgressLabel.text = "\(progressStatus) %"
if progressStatus == 100
{
cell.downloadProgressLabel.text = ""
}
})
}
}
}
cellForRowAtIndexPath method
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell
{
let cell:WallTableViewCell = tableView.dequeueReusableCellWithIdentifier("cell", forIndexPath: indexPath) as WallTableViewCell
let userPost = timeLineData.objectAtIndex(indexPath.section) as PFObject
if (!cell.isDownloadingInProgress)
cell.updateCellWithUserPost(userPost)
return cell
}
Note: I don't know Swift too much as I am a pure Objective-C programmer. Let me know if you have any questions regarding the answer
Try using SDWebImages . It will handle images for your application properly .
Related
I'm creating an e-commerce app with (Moltin.com) SDK, I set every thing well as it shown in the documentation but now I need to load multi images of single product in table view with custom cell, I set the shown code below and all I can get is a single image my app ignore load the other images view controller code is
class vc: UIViewController , UITableViewDelegate, UITableViewDataSource {
var productDict:NSDictionary?
#IBOutlet weak var tableview: UITableView!
fileprivate let MY_CELL_REUSE_IDENTIFIER = "MyCell"
fileprivate var productImages:NSArray?
override func viewDidLoad() {
super.viewDidLoad()
tableview.delegate = self
tableview.dataSource = self
Moltin.sharedInstance().product.listing(withParameters: productDict!.value(forKeyPath: "url.https") as! [String : Any]!, success: { (response) -> Void in
self.productImages = response?["result"] as? NSArray
self.tableview?.reloadData()
}) { (response, error) -> Void in
print("Something went wrong...")
}
}
func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
if productImages != nil {
return productImages!.count
}
return 0
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: MY_CELL_REUSE_IDENTIFIER, for: indexPath) as! MyCell
let row = (indexPath as NSIndexPath).row
let collectionDictionary = productImages?.object(at: row) as! NSDictionary
cell.setCollectionDictionary(collectionDictionary)
return cell
}
and my custom cell code is
class MyCell: UITableViewCell {
#IBOutlet weak var myImage: UIImageView!
override func awakeFromNib() {
super.awakeFromNib()
// Initialization code
}
func setCollectionDictionary(_ dict: NSDictionary) {
// Set up the cell based on the values of the dictionary that we've been passed
// Extract image URL and set that too...
var imageUrl = ""
if let images = dict.value(forKey: "images") as? NSArray {
if (images.firstObject != nil) {
imageUrl = (images.firstObject as! NSDictionary).value(forKeyPath: "url.https") as! String
}
}
myImage?.sd_setImage(with: URL(string: imageUrl))
}
Can anyone show me where is the issue that doesn't let me get all the images of my product?
I'm using SWIFT 3, with XCode
In the code below you are always getting one URL from images array (firstObject).
if let images = dict.value(forKey: "images") as? NSArray {
if (images.firstObject != nil) {
imageUrl = (images.firstObject as! NSDictionary).value(forKeyPath: "url.https") as! String
}
}
myImage?.sd_setImage(with: URL(string: imageUrl))
If I understand correctly you should get every image in images array by the indexPath.row of your tableView.
For example add new parameter to method like this:
func setCollection(with dict: NSDictionary, and index: Int) {
// Set up the cell based on the values of the dictionary that we've been passed
// Extract image URL and set that too...
var imageUrlString = ""
if let images = dict.value(forKey: "images") as? Array<NSDictionary>, images.count >= index {
guard let lImageUrlString = images[index]["url.https"] else { return }
imageUrlString = lImageUrlString
}
guard let imageURL = URL(string: imageUrl) else { return }
myImage?.sd_setImage(with: imageURL)
}
Than when call this method in cellForRow just add indexPath.row to the second param.
But if you want show multiple images in one cell you should add more imageViews to the custom cell or use UICollectionView.
Just ping me if I don't understand you clear.
I currently have a tableView being loaded from Firebase. This content includes a picture which, when the user scrolls, will change until it settles on its final image. I would assume this would be assigning an image to each cell before it can succesfully load each cell, but have not been able to come up with a work around.
The current code that I have to populate the tableView is as follows:
TableView
import UIKit
import FirebaseAuth
import FirebaseStorage
class Articles: UITableViewController {
var vcType:String = "Home"
var rooms = [Room]()
var articleCell = ArticlesCell()
#IBOutlet weak var menuButton: UIBarButtonItem!
override func viewDidLoad() {
super.viewDidLoad()
if self.vcType == "Home"
{
self.rooms += ArticlesManager.sharedClient.rooms
}
else
{
if let obj = ArticlesManager.sharedClient.catRooms[self.vcType.lowercased()] //as? [Room]
{
self.rooms += obj
}
}
self.tableView.reloadData()
ArticlesManager.sharedClient.blockValueChangeInRoomArray = {
newRoom in
if self.vcType == "Home"
{
self.rooms.append(newRoom)
self.rooms.sort(by: {
if $0.created_Date == nil
{
return false
}
if $1.created_Date == nil
{
return true
}
return $0.created_Date.compare($1.created_Date) == ComparisonResult.orderedDescending
})
}
else
{
if self.vcType.lowercased() == newRoom.category
{
self.rooms.append(newRoom)
self.rooms.sort(by: {
if $0.created_Date == nil
{
return false
}
if $1.created_Date == nil
{
return true
}
return $0.created_Date.compare($1.created_Date) == ComparisonResult.orderedDescending
})
self.tableView.reloadData()
}
}
}
}
override func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return rooms.count
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
if (indexPath as NSIndexPath).row == 0 {
let cell2 = tableView.dequeueReusableCell(withIdentifier: "featured", for: indexPath) as! featuredCell
let room = rooms[(indexPath as NSIndexPath).row]
cell2.configureCell(room)
return cell2
} else {
let cell = tableView.dequeueReusableCell(withIdentifier: "Cell", for: indexPath) as! ArticlesCell
let room = rooms[(indexPath as NSIndexPath).row]
cell.configureCell(room)
return cell
}
Data
import Foundation
import Firebase
import FirebaseAuth
let roomRef = FIRDatabase.database().reference()
class Data {
static let dataService = Data()
fileprivate var _BASE_REF = roomRef
fileprivate var _ROOM_REF_ = roomRef.child("rooms")
fileprivate var _BASE_REF2 = roomRef
fileprivate var _ROOM_REF_2 = roomRef.child("contents")
var BASE_REF: FIRDatabaseReference {
return _BASE_REF
}
var ROOM_REF: FIRDatabaseReference {
return _ROOM_REF_
}
var storageRef: FIRStorageReference {
return FIRStorage.storage().reference()
}
var fileURL: String!
func fetchData(_ callback: #escaping (Room) -> ()) {
Data.dataService.ROOM_REF.observe(.childAdded, with: { (snapshot) in
print("snapshot.value - \(snapshot))")
let room = Room(key: snapshot.key, snapshot: snapshot.value as! Dictionary<String, AnyObject>)
callback(room)
})
}
}
TableViewCell
import UIKit
import FirebaseStorage
class featuredCell: UITableViewCell {
#IBOutlet weak var featuredImage: UIImageView!
#IBOutlet weak var featuredTitle: UITextView!
#IBOutlet weak var featuredAuthor: UITextField!
#IBOutlet weak var featuredDate: UITextField!
#IBOutlet weak var featuredContent: UITextView!
class var defaultHeight: CGFloat { get { return ((UIScreen.main.fixedCoordinateSpace.bounds.height - 64) / 5) * 3}}
func configureCell(_ room: Room) {
self.featuredTitle.text = room.title
self.featuredDate.text = room.date
self.featuredAuthor.text = room.author
self.featuredContent.text = room.story
if let imageURL = room.thumbnail {
if imageURL.hasPrefix("gs://") {
FIRStorage.storage().reference(forURL: imageURL).data(withMaxSize: INT64_MAX, completion: { (data, error) in
if let error = error {
print("Error downloading: \(error)")
return
}
self.featuredImage.image = UIImage.init(data: data!)
})
} else if let url = URL(string: imageURL), let data = try? Foundation.Data(contentsOf: url) {
self.featuredImage.image = UIImage.init(data: data)
}
}
}
}
Thank you for your help!
This is a normal behavior of tableviews when working with async downloading during tableview load or scrolling. You've to just clear your image before loading and keep the images datas in Cache when they've downloaded once for a efficient network charge. If you do not use caching, tableview always "re-download" the image when the cell is going to reused. Please see the example;
public func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "cell") as! TableViewCell
let urle = self.filteredFlats[indexPath.row].flatThumbnailImage?.imageDownloadURL
if let url = urle
{
cell.imgv.image = nil
if let imagefromCache = imageCache.object(forKey: url as AnyObject) as? UIImage
{
cell.imgv.image = imagefromCache
}
else
{
cell.imgv.image = nil
let urlURL = URL(string: (url))
URLSession.shared.dataTask(with: urlURL!, completionHandler: { (data, response, error) in
if error != nil
{
print(error.debugDescription)
return
}
DispatchQueue.main.async {
let imagetoCache = UIImage(data:data!)
self.imageCache.setObject(imagetoCache!, forKey: url as AnyObject)
cell.imgv.image = imagetoCache
}
}).resume()
}
}
return cell
}
this code is copied from my project. So i'm caching the image when it is already downloaded. Also i do not redownload it when cell is reused. Just checking if it is cached or not. So you can use this apporach for a behaviour that satisfy your requirements.
I'm a beginner using ReactiveCocoa with Swift for the first time. I'm building an app showing a list of movies and I'm using the MVVM pattern. My ViewModel looks like this:
class HomeViewModel {
let title:MutableProperty<String> = MutableProperty("")
let description:MutableProperty<String> = MutableProperty("")
var image:MutableProperty<UIImage?> = MutableProperty(nil)
private var movie:Movie
init (withMovie movie:Movie) {
self.movie = movie
title.value = movie.headline
description.value = movie.description
Alamofire.request(.GET, movie.pictureURL)
.responseImage { response in
if let image = response.result.value {
print("image downloaded: \(image)")
self.image.value = image
}
}
}
}
and I would like to configure my cells in the UITableView like this:
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("MovieCell", forIndexPath: indexPath) as! MovieCell
let movie:Movie = movieList[indexPath.row]
let vm = HomeViewModel(withMovie: movie)
// fill cell with data
vm.title.producer.startWithNext { (newValue) in
cell.titleLabel.text = newValue
}
vm.description.producer.startWithNext { (newValue) in
cell.descriptioLabel.text = newValue
}
vm.image.producer.startWithNext { (newValue) in
if let newValue = newValue {
cell.imageView?.image = newValue as UIImage
}
}
return cell
}
Is this the right approach for Reactive Cocoa? Do I need to declare Title and description as Mutable or just image (being the only one changing). I think I could use binding but I'm not sure how to proceed.
to do this using Reactive Cocoa + MVVM patterns i would first move all the logic to configure the cell from its viewmodel into the cell class itself. and then remove the MutableProperties from the viewModel (they aren't actually mutable and we dont need those signals). and for the image expose a signal producer that will perform the network request to fetch the image when start() is called, rather than implicitly fetching it when init is called on the ViewModel, giving us something like
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("MovieCell", forIndexPath: indexPath) as! MovieCell
cell.viewModel = self.viewModelForIndexPath(indexPath)
return cell
}
private func viewModelForIndexPath(indexPath: NSIndexPath) -> MovieCellViewModel {
let movie: Movie = movieList[indexPath.row]
return HomeViewModel(movie: movie)
}
and then
class MovieCell: UITableViewCell
#IBOutlet weak var titleLabel: UILabel
#IBOutlet weak var descriptionLabel: UILabel
#IBOutlet weak var imageView: UIImageView
var viewModel: MovieCellViewModel {
didSet {
self.configureFromViewModel()
}
}
private func configureFromViewModel() {
self.titleLabel.text = viewModel.title
self.descriptionLabel.text = viewModel.description
viewModel.fetchImageSignal()
.takeUntil(self.prepareForReuseSignal()) //stop fetching if cell gets reused
.startWithNext { [weak self] image in
self?.imageView.image = image
}
}
//this could also go in a UITableViewCell extension if you want to use it other places
private func prepareForReuseSignal() -> Signal<(), NoError> {
return Signal { observer in
self.rac_prepareForReuseSignal // reactivecocoa builtin function
.toSignalProducer() // obj-c RACSignal -> swift SignalProducer
.map { _ in () } // AnyObject? -> Void
.flatMapError { _ in .empty } // NSError -> NoError
.start(observer)
}
}
}
and in the ViewModel
struct HomeViewModel {
private var movie: Movie
var title: String {
return movie.headline
}
var description: String {
return movie.description
}
func fetchImageSignal() -> SignalProducer<UIImage, NSError> {
return SignalProducer { observer, disposable in
Alamofire.request(.GET, movie.pictureURL)
.responseImage { response in
if let image = response.result.value {
print("image downloaded: \(image)")
observer.sendNext(image) //send the fetched image on the signal
observer.sendCompleted()
} else {
observer.sendFailed( NSError(domain: "", code: 0, userInfo: .None)) //send your error
}
}
}
}
I have a problem with reload data in tableView in my simple swift app for iOS.
If I for the first time enter the city name into the cityTextField and press the getDataButton, so the data displays correctly, but If I enter the new city name into cityTextField and press button, so data are still the same like for the first city.
ViewController
import UIKit
class ViewController: UIViewController,UITableViewDelegate {
var arrDict :NSMutableArray=[]
#IBOutlet weak var cityTextField: UITextField!
#IBOutlet weak var weatherTableView: UITableView!
#IBAction func getDataButton(sender: AnyObject) {
weatherDataSource("http://api.openweathermap.org/data/2.5/forecast?q=" + cityTextField.text! + "&appid=<app id>")
}
override func viewDidLoad() {
super.viewDidLoad()
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
func weatherDataSource(urlString: String) {
let urlUTF = urlString.stringByAddingPercentEscapesUsingEncoding(NSUTF8StringEncoding)
let url = NSURL(string: urlUTF!)
let query = NSURLSession.sharedSession().dataTaskWithURL(url!) { (data, response, error) in dispatch_async(dispatch_get_main_queue(), { ()
self.loadDataWeather(data!)
self.weatherTableView.reloadData()
})
}
query.resume()
}
func loadDataWeather(dataPocasi: NSData){
do {
if let json = try NSJSONSerialization.JSONObjectWithData(dataPocasi, options: []) as? NSDictionary {
print(json)
for var i = 0 ; i < (json.valueForKey("list") as! NSArray).count ; i++
{
arrDict.addObject((json.valueForKey("list") as! NSArray) .objectAtIndex(i))
}
}
} catch {
print(error)
}
}
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int
{
return arrDict.count
}
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell
{
var cell : TableViewCell! = tableView.dequeueReusableCellWithIdentifier("Cell") as! TableViewCell
if(cell == nil)
{
cell = NSBundle.mainBundle().loadNibNamed("Cell", owner: self, options: nil)[0] as! TableViewCell;
}
let strTitle : NSNumber=arrDict[indexPath.row] .valueForKey("dt") as! NSNumber
let epocTime = NSTimeInterval(strTitle)
let myDate = NSDate(timeIntervalSince1970: epocTime)
let dateFormatter = NSDateFormatter()
dateFormatter.dateFormat = "hh:mm"
let dateString = dateFormatter.stringFromDate(myDate)
cell.dayLabel.text=dateString
let strDescription : NSDictionary=arrDict[indexPath.row] .objectForKey("main") as! NSDictionary
if let bla = strDescription["temp"]{
cell.tempLabel.text=bla.stringValue
}
return cell as TableViewCell
}
}
TableViewCell
import UIKit
class TableViewCell: UITableViewCell{
#IBOutlet weak var dayLabel: UILabel!
#IBOutlet weak var tempLabel: UILabel!
}
You are not instantiating your tableView delegate. Make sure you call self.weatherTableView.delegate = self inside viewDidLoad().
Also, you should create a new arrDict every time you load your data. self.arrDict = [].
In case the above ajustments dont work you should get some time debugging it. Make sure the second request is loading the data and, if so, your self.weatherTableView.reloadData() might not being called. You could try moving it to loadDataWeather().
You can reload tableview in "loadDataWether()" function.
Like,
func loadDataWeather(dataPocasi: NSData){
do {
if let json = try NSJSONSerialization.JSONObjectWithData(dataPocasi, options: []) as? NSDictionary {
print(json)
for var i = 0 ; i < (json.valueForKey("list") as! NSArray).count ; i++
{
arrDict.addObject((json.valueForKey("list") as! NSArray) .objectAtIndex(i))
}
}
} catch {
print(error)
}
self.weatherTableView.reloadData()
}
// import UIKit
import Parse
import Foundation
class EditFriendsController: UITableViewController {
var allUsers:NSArray = [] // NSArray *allUsers
var currentUser = PFUser.currentUser()
var friends:NSMutableArray = [] // used in FriendsController
var profileImages = [PFFile]()
override func viewDidLoad() {
super.viewDidLoad()
}
override func viewWillAppear(animated: Bool) {
super.viewWillAppear(animated)
// PFQuery *query = [PFUser query] in objective C
var query = PFUser.query()
query!.orderByAscending("username")
query!.findObjectsInBackgroundWithBlock {
(objects: [AnyObject]?, error: NSError?) -> Void in
if error != nil {
// Log details of the failure
println("Error: \(error!)\(error!.userInfo)")
} else {
// The find succeeded.
println("Successfully retrieved \(objects!.count) scores.")
self.allUsers = objects!
// println("\(self.allUsers)")
self.animateTable() // include self.tableView.reloadData()
}
}
self.currentUser = PFUser.currentUser()
}
// MARK: - Table view animate function
func animateTable() {
tableView.reloadData()
let cells = tableView.visibleCells()
let tableHeight:CGFloat = tableView.bounds.size.height
for transformBefore in cells {
let cell: UITableViewCell = transformBefore as! UITableViewCell
cell.transform = CGAffineTransformMakeTranslation(0, tableHeight)
}
var index = 0
for transformAfter in cells {
let cell: UITableViewCell = transformAfter as! UITableViewCell
UIView.animateWithDuration(1.5, delay: 0.05 * Double(index), usingSpringWithDamping: 0.8, initialSpringVelocity: 0, options: nil, animations: { () -> Void in
cell.transform = CGAffineTransformMakeTranslation(0, 0)
}, completion: nil)
index += 1
}
}
// MARK: - Table view data source
override func numberOfSectionsInTableView(tableView: UITableView) -> Int {
return 1
}
override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return self.allUsers.count
}
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
var cell = tableView.dequeueReusableCellWithIdentifier("Cell", forIndexPath: indexPath) as! EditFriendsProfileViewCell
var user = self.allUsers[indexPath.row] as! PFUser
cell.usernameLabel.text = user.username!
// cell.profileImageView.image = UIImage(named: profileImages[indexPath.row])
if let userPicture = PFUser.currentUser()?["photo"] as? PFFile {
userPicture.getDataInBackgroundWithBlock({
(imageData:NSData?, error:NSError?) -> Void in
var img:UIImageView = UIImageView()
if (error == nil) {
cell.profileImageView.image = UIImage(data: imageData!)
} else {
}
})
}
// image cornerRadius
cell.profileImageView.layer.cornerRadius = 10
cell.profileImageView.clipsToBounds = true
var myFriend = isFriend(user)
cell.accessoryType = myFriend ? .Checkmark : .None
//cell.checkImageView.image = myFriend ? UIImage(named: "checkedFilled.png") : UIImage(named: "checkedWhite.png")
return cell
}
override func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
self.tableView.deselectRowAtIndexPath(indexPath, animated: false)
var cell = tableView.cellForRowAtIndexPath(indexPath) as! EditFriendsProfileViewCell
var user = self.allUsers[indexPath.row] as! PFUser
var friendsRelation = self.currentUser!.relationForKey("friendsRelation")
var myFriend = isFriend(user)
if (myFriend) {
// remove process
// 1. Remove the checkmark
cell.accessoryType = UITableViewCellAccessoryType.None
// cell.imageView?.image = UIImage(named: "checkedWhite.png")
// 2. Remove from array of friend
var friend = PFUser()
for friend in self.friends {
if friend.objectId == user.objectId {
self.friends.removeObject(friend)
break;
}
}
// 3. Remove from the backend
friendsRelation.removeObject(user)
} else {
// add them
cell.accessoryType = UITableViewCellAccessoryType.Checkmark
// cell.imageView?.image = UIImage(named: "checkedFilled.png")
self.friends.addObject(user)
friendsRelation.addObject(user)
}
self.currentUser!.saveInBackgroundWithBlock {
(success: Bool, error: NSError?) -> Void in
if (success) {
// The post has been added to the user's likes relation.
} else {
// There was a problem, check error.description
println("Error: \(error!)\(error!.userInfo)")
}
}
}
// MARK: - Table view Helper Methods
func isFriend(user: PFUser!) -> Bool {
var friend = PFUser()
for friend in self.friends {
if friend.objectId == user.objectId {
return true;
}
}
return false;
}
}
All profile pictures are loaded as same image although all different stores are stored in Parse.
Please help me.
you are setting photo of currently logged-in user , set user?["photo"] in cellForRowAtIndexPath
if let userPicture = user?["photo"] as? PFFile{
}