Parse check if user already tapped button - ios

I am trying to implement a like feature in my app using parse. If a user taps the vote up button. The label increases changing the like number in parse side as well. However with my code a user can tap many times to increase the like. I would like to make it detect that user has tapped and make the like button disabled. To do that I have made a class in parse called "Liked". I made a username, imageId both a string column and a likeStatus as a Boolean . However I can't make is so that if a user likes any image it will add new item to it with userId, ImageId and likeStatus.
This is the Collection View code
func collectionView(collectionView: UICollectionView, cellForItemAtIndexPath indexPath: NSIndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCellWithReuseIdentifier("newview", forIndexPath: indexPath) as! NewCollectionViewCell
let item = self.votes[indexPath.row]
// Display the country name
if let value = item["imageText"] as? String {
cell.postsLabel.text = value
}
// Display "initial" flag image
var initialThumbnail = UIImage(named: "question")
cell.postsImageView.image = initialThumbnail
cell.complition = {
self.likeButton(indexPath)
}
if let votesValue = item["votes"] as? Int
{
cell.votesLabel?.text = "\(votesValue)"
}
// Fetch final flag image - if it exists
if let value = item["imageFile"] as? PFFile {
cell.postsImageView.file = value
cell.postsImageView.loadInBackground({ (image: UIImage?, error: NSError?) -> Void in
if error != nil {
cell.postsImageView.image = image
}
})
}
return cell
}
/*
==========================================================================================
Segue methods
==========================================================================================
*/
func likeButton(indexPath:NSIndexPath)
{
let cell = self.collectionView.cellForItemAtIndexPath(indexPath) as! NewCollectionViewCell
let object = self.votes[indexPath.row]
if let likes = object["votes"] as? Int
{
object["votes"] = likes + 1
object.saveInBackgroundWithBlock{ (success:Bool,error:NSError?) -> Void in
println("Data saved")
}
cell.votesLabel?.text = "\(likes + 1)"
}
else
{
object["votes"] = 1
object.saveInBackgroundWithBlock{ (success:Bool,error:NSError?) -> Void in
println("Data saved")
}
cell.votesLabel?.text = "1"
}
}
and this is the cell code
#IBAction func vote(sender: AnyObject) {
if self.complition != nil
{
self.complition!()
}
}
}
Any tips or How am I able to do this in code?Thank you.

The way I did this was by using a class in Parse that I called "UserLikeActivity" or something to that effect, and in it, it had a column pointer to the user that did the liking, a pointer to the actitivy that was liked (in my case it was a post), a type (indicating whether it was an upvote, downvote, follow, etc), and a pointer to the user who created the activity that was liked.
Now, when I was querying Parse to set my tables up, not only did I query the class that contained all the posts, but I also queried this class, which I then saved and used to determine the button state. So for every cell, if the activity had already been liked, I disabled the button. Hopefully this will help you get going in the right direction since you've asked this question about 7 times.

Related

Issue trying to complete Firebase Storage download before showing tableview

I have a table view where depending on the cell class it will download an image from Firebase. I've noticed when using the app that cells with the same cell identifier will show the previous downloaded image before showing the new one. This is what I have before changing it.
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
if tableData[indexPath.row]["Image"] != nil {
let cell = tableView.dequeueReusableCell(withIdentifier: "imageNotesData", for: indexPath) as! ImageNotesCell
cell.notes.delegate = self
cell.notes.tag = indexPath.row
cell.notes.text = tableData[indexPath.row]["Notes"] as! String
guard let imageFirebasePath = tableData[indexPath.row]["Image"] else {
return cell }
let pathReference = Storage.storage().reference(withPath: imageFirebasePath as! String)
pathReference.getData(maxSize: 1 * 1614 * 1614) { data, error in
if let error = error {
print(error)
} else {
let image = UIImage(data: data!)
cell.storedImage.image = image
}
}
return cell
}
else {
let cell = tableView.dequeueReusableCell(withIdentifier: "notesData", for: indexPath) as! NotesCell
//let noteString = tableData[indexPath.row]["Notes"] as! String
cell.notes.text = tableData[indexPath.row]["Notes"] as! String
cell.notes.delegate = self
cell.notes.tag = indexPath.row
return cell
}
}
Knowing that this is not a good user experience and that it looks clunky, I tried to move the pathReference.getData to where I setup the data but the view appears before my images finish downloading. I have tried to use a completion handler but I'm still having issues.
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(true)
getSectionData(userID: userID, city: selectedCity, completion: {(sectionString) in
self.setupTableCellView(userID: userID, city: selectedCity, section: sectionString) { (tableData) in
DispatchQueue.main.async(execute: {
self.cityName?.text = selectedCity
self.changeSections.setTitle(sectionString, for: .normal)
self.currentSectionString = sectionString
self.setupTableData(tableDataHolder: tableData)
})
}
})
}
func setupTableCellView(userID: String, city: String, section: String, completion: #escaping ([[String:Any]]) -> () ) {
let databaseRef = Database.database().reference().child("Users").child(userID).child("Cities").child(city).child(section)
var indexData = [String:Any]()
var indexDataArray = [[String:Any]]()
databaseRef.observeSingleEvent(of: .value, with: { (snapshot) in
for dataSet in snapshot.children {
let snap = dataSet as! DataSnapshot
//let k = snap.key
let v = snap.value
indexData = [:]
for (key, value) in v as! [String: Any] {
//indexData[key] = value
if key == "Image" {
//let pathReference = Storage.storage().reference(withPath: value as! String)
print("before getImageData call")
self.getImageData(pathRef: value as! String, completion: {(someData) in
print("before assigning indexData[key]")
indexData[key] = someData
print("after assigning indexData[key]")
})
} else {
indexData[key] = value
}
}
indexDataArray.append(indexData)
}
completion(indexDataArray)
})
}
func getImageData(pathRef: String, completion: #escaping(UIImage) -> ()) {
let pathReference = Storage.storage().reference(withPath: pathRef as! String)
pathReference.getData(maxSize: 1 * 1614 * 1614, completion: { (data, error) in
if let error = error {
print(error)
} else {
let image = UIImage(data:data!)
print("called before completion handler w/ image")
completion(image!)
}
})
}
I don't know if I am approaching this the right way but I think I am. I'm also guessing that the getData call is async and that is why it will always download after showing the table view.
You can't do this.
Make the request from Firebase.
Over time, you will get many replies - all the information and all the changing information.
When each new item arrives - and don't forget it may be either an addition or deletion - alter your table so that it displays all the current items.
That's OCC!
OCC is "occasionally connected computing". A similar phrase is "offline first computing". So, whenever you use any major service you use every day like Facebook, Snapchat, etc that is "OCC": everything stays in sync properly whether you do or don't have bandwidth. You know? The current major paradigm of device-cloud computing.
Edit - See Fattie's comments about prepareForReuse()!
With reusable table cells, the cells will at first have the appearance they do by default / on the xib. Once they're "used", they have whatever data they were set to. This can result in some wonky behavior. I discovered an issue where in my "default" case from my data, I didn't do anything ecause it already matched the xib, but if the data's attributes were different, I updated the appearance. The result was that scrolling up and down really fast, some things that should have had the default appearance had the changed appearance.
One basic solution to just not show the previous image would be to show a place holder / empty image, then call your asynchronous fetch of the image. Not exactly what you want because the cell will still show up empty...
Make sure you have a local store for the images, otherwise you're going to be making a server request for images you already have as you scroll up and down!
I'd recommend in your viewDidLoad, call a method to fetch all of your images at once, then, once you have them all, in your success handler, call self.tableview.reloadData() to display it all.

Tableview Like Snapchat Send Feature (Multiple Selection and Swipeable Label)

In my Xcode Project I will like to have a similar view like Snapchat's "Send To..." screen (I have attached a screenshot). I have already made a tableview and populate it and have allowed multiple selection on. I am currently having trouble with two things:
1) Multiple Selection: I can select an cell I want, but when I tap on the search bar and start typing, all my previous selections go away. I am assuming that I need to add all of the names in a array and somehow communicate the array with the table so it shows if this username is in the array then make it selected in the tableview. But I am not sure how to do that. How can I do this?
2) Sending to Bottom Bar (blue in photo): As you may know, in Snapchat as you press on which users you want to send the snap to, their names get added to the bar at the bottom, as you fill up the bar, it because swipe able where you can horizontally scroll through the names you have added. I can append the names to an array and show the array in a label like theirs, but I do not know how to make it so a user can horizontally scroll through it.How do I implement this same feature?
Feel free to answer ANY of the questions! You do not need to do all of them, I just need them answered. Here's my code so far:
class User {
var userID:String?
var userFullName:String?
var userUsername:String?
var userProfileImage:PFFile?
var isPrivate:Bool
init(userID : String, userFullName : String, userUserName : String, userProfileImage : PFFile, isPrivate : Bool) {
self.userID = userID
self.userFullName = userFullName
self.userUsername = userUserName
self.userProfileImage = userProfileImage
self.isPrivate = isPrivate
}
}
var userArray = [User]()
func loadFriends() {
//STEP 1: Find friends
let friendsQuery = PFQuery(className: "Friends") //choosing class
friendsQuery.whereKey("friendOne", equalTo: PFUser.current()?.objectId ?? String()) //finding friends
friendsQuery.limit = self.page //number of users intitally showing
friendsQuery.findObjectsInBackground (block: { (objects, error) -> Void in
if error == nil { //if no error
//clean up
self.friendsArray.removeAll(keepingCapacity: false)
//STEP 2: Find related objects depending on query setting
for object in objects! {
self.friendsArray.append(object.value(forKey: "friendTwo") as! String) //hold array info of friend
}
//STEP 3: Find friend info
let query = PFUser.query()
query?.whereKey("objectId", containedIn: self.friendsArray)
query?.addDescendingOrder("createdAt") //how to order users
query?.findObjectsInBackground(block: { (objects, error) -> Void in
if error == nil {
for object in objects! {
var user : User
let fullname = (object.value(forKey: "fullname") as! String)
let username = (object.object(forKey: "username") as! String)
let profilePhoto = (object.object(forKey: "profilePhoto") as! PFFile)
let objectID = (object.objectId!)
let isPrivate = (object.object(forKey: "isPrivate") as! Bool)
user = User(userID: objectID, userFullName: fullname, userUserName: username, userProfileImage: profilePhoto, isPrivate: isPrivate)
self.userArray.append(user)
}
self.tableView.reloadData()
} else {
print(error!)
}
})
} else {
print(error!)
}
})
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "Cell") as! FriendCell
let user = userArray[indexPath.row]
//add user info to cells
cell.fullnameLabel.text = user.userFullName
cell.usernameLabel.text = user.userUsername
cell.objectID = user.userID!
cell.isPrivate = user.isPrivate
user.userProfileImage?.getDataInBackground (block: { (data, error) in
if error == nil {
cell.profilePhoto.image = UIImage(data: data!)
}
})
})
}
1) Multiple Selection:
You should have a User class (e.g User) that holds user properties instead of maintaining array for each property. Store User object in a Array. User class could be like below:
class User {
var userID:String
var userFullName:String
var userName:String
var userProfileImageUrl:String
init(userID:String,userFullName:String,userName:String,userProfileImageUrl:String) {
self.userID = userID
self.userFullName = userFullName
self.userName = userName
self.userProfileImageUrl = userProfileImageUrl
}
}
You could have a User extension to check if that user is selected or not(e.g isSelected).
import UIKit
import Foundation
private var selectedKey: UInt8 = 0
extension User {
var isSelected:Bool{
get {
return objc_getAssociatedObject(self, &selectedKey) as! Bool
}
set {
objc_setAssociatedObject(self, &selectedKey, newValue, .OBJC_ASSOCIATION_RETAIN_NONATOMIC)
}
}
}
Now in your func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell check that user.isSelected == true/false and update your selected/deselected image accordingly.
And update the value of isSelected in func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath)
2) Sending to Bottom Bar:
For bottom bar add a UICollectionView as a subview in UIView. Create a class overriding UICollectionViewCell that holds a UILabel. You can add flow layout in UICollectionView.
I have given just an idea to start with.Hope it will help you.
I think, you set bool check for every cell in tableView. If cell load again, it will not show check. Because, It check is false.

Why does data returned from coredata become nil after tableview scroll in swift?

Update Note: This question does not seem to be a duplicate of How can I fix crash when tap to select row after scrolling the tableview? because my issue is specifically about one of my CoreData objects going nil after the table scrolls. But the cell returns data as long as the app doesnt crash due to the nil from the topic object.
Basically this part fails: let estimatedSkills = topic.topicEstimatedSkill and let topic = self.topics!.object(at: indexPath.row) as! Topic even though at first, a debugprint shows that the object is not nil, after scroll, self.topic becomes nil.
Original:
I hope you can help me because I am a beginner in Swift and apple development in general.
I inherited an ios app that didnt work because the structure of data returned from our server changed. The previous developers cant be reached, so I am trying to make out what to do here. On top of that, in the middle of development, apple forced me to update to swift3 and xcode8 changing the gamerules making everything even more confusing.
So basically I have a tableview that gets data from an object fetched from CoreData. It fills out the cells when initiated, but scrolling makes the data from the object return nil.
The object in question is named Topic
and the code fails at:
//TODO - this sometimes gives nil but shouldnt
if let estimatedSkills = topic.topicEstimatedSkill {
value = estimatedSkills.doubleValue * Double(cell.starViewContainer.subviews.count);
debugPrint("success getting estimated skills!" , indexPath, estimatedSkills)
} else {
debugPrint("Didnt get estimated skills :(")
}
Then when I return to the original cells, the info in those are gone too.
Here's the tableview function:
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: Identifiers.cells.superTrainer.rawValue, for: indexPath) as! SuperTrainerOverViewCell;
cell.backgroundColor = UIColor.clear;
let topic = self.topics!.object(at: indexPath.row) as! Topic;
cell.titleLabel.text = topic.topicName;
var value = 0.0
//TODO - this sometimes gives nil but shouldnt
if let estimatedSkills = topic.topicEstimatedSkill {
value = estimatedSkills.doubleValue * Double(cell.starViewContainer.subviews.count);
debugPrint("success getting estimated skills!" , indexPath, estimatedSkills)
} else {
debugPrint("Didnt get estimated skills :(")
}
let wholeStar = Int(floor(value));
for index in (0..<wholeStar) {
let imageView = cell.starViewContainer.subviews[index] as! UIImageView;
imageView.image = UIImage(named: "icon-star-100");
}
if(wholeStar < cell.starViewContainer.subviews.count) {
let decimal = fmod(value, 1);
var image = UIImage(named: "icon-star-100");
if(decimal < 0.15) {
image = UIImage(named: "icon-star-0");
}else if(decimal >= 0.15 && decimal < 0.4) {
image = UIImage(named: "icon-star-25");
}else if(decimal >= 0.4 && decimal < 0.65) {
image = UIImage(named: "icon-star-50");
}else if(decimal >= 0.65 && decimal < 0.80) {
image = UIImage(named: "icon-star-75");
}
let imageView = cell.starViewContainer.subviews[wholeStar] as! UIImageView;
imageView.image = image;
}
return cell;
}
The class has a topics property which gets set at:
override func viewDidLoad() {
self.navigationItem.title = "SUPERTRAINER".localized;
self.tableView.backgroundColor = UIColor.init(rgba: hexColors.gray.rawValue);
if(Utility.isConnectedToNetwork()) {
self.getSuperTrainerData(student: self.student!);
} else {
self.topics = Topic.getTopics(student: self.student!, context: NetworkService.sharedInstance.coreDataHandler.context!);
Utility.showNoConnectionAlertView();
}
self.tableView.tableFooterView = UIView(frame: CGRect.zero);
}
// MARK: Custom Methods
func getSuperTrainerData(student: Student) {
_ = SwiftSpinner.show("FETCHING_DATA".localized);
Utility.backgroundThread( background: { () -> Void in
self.networkService.getSuperTrainerData(student: student) { (complet, returnDics, errorMessage) -> Void in
if(complet) {
self.removeSuperTrainerData();
self.createSuperTrainerData(dics: returnDics!);
} else {
Utility.showAlertView(title: "LOGIN_FAILED_TITLE".localized, message: errorMessage);
}
}
}) { () -> Void in
self.networkService.coreDataHandler.saveContext();
self.topics = Topic.getTopics(student: self.student!, context:self.networkService.coreDataHandler.context!)!;
SwiftSpinner.hide();
self.tableView.reloadData();
}
}
Anyone have any ideas? :) Im too new at swift to figure out all of this quickly right now, so any help is super appreciated!
I found out eventually that it was actually a threading(concurrence) problem.
Basically, in the getSuperTrainerData function, a bunch of objects were supposed to be created. Given that they returned nill all the time, the ViewController would of course refuse to create the rows.. however, entering the same view twice would have given the app time to store and cache the objects returned from a network call.
I make a call to Utility.backgroundThread which is just a wrapper for dispatchQueue. This means that networkService was placed inside a background thread. But inside networkService there is a call to urlSession. Call to servers create their own background threads, so even though I called my server call throuhg a background thread, it created its own background thread and never returned to the main call.
The solution that I used was to just make a server call, and place the background-object-creation call in the completion handler like so:
self.networkService.getSuperTrainerData(student: student) { (complet, returnDics, errorMessage) -> Void in
if(complet) {
DispatchQueue.global(qos: DispatchQoS.userInitiated.qosClass ).async {
self.removeSuperTrainerData();
self.createSuperTrainerData(dics: returnDics!);
DispatchQueue.main.async( execute: {
print("main queue without completion")
self.networkService.coreDataHandler.saveContext();
self.topics = Topic.getTopics(student: self.student!, context:self.networkService.coreDataHandler.context!)!;
SwiftSpinner.hide();
self.tableView.reloadData();
})
}
} else {
Utility.showAlertView(title: "LOGIN_FAILED_TITLE".localized, message: errorMessage);
}
}
Hope this helps someone :)

SDWebImage implementation in parse using Swift

I am using parse to retrieve my images and labels and display it on a collection view. The problem was that the collection view loads all the images and labels at once making the load time long and memory usage was high. I was thinking that I would load 10 cells each time however I was recommended to use SDWebImage to make the app lighter. However I don't know how to implement it with parse using swift. I am suspecting that I would put some code in this piece of code below
func collectionView(collectionView: UICollectionView, cellForItemAtIndexPath indexPath: NSIndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCellWithReuseIdentifier("newview", forIndexPath: indexPath) as! NewCollectionViewCell
let item = self.votes[indexPath.row]
let gesture = UITapGestureRecognizer(target: self, action: Selector("onDoubleTap:"))
gesture.numberOfTapsRequired = 2
cell.addGestureRecognizer(gesture)
// Display "initial" flag image
var initialThumbnail = UIImage(named: "question")
cell.postsImageView.image = initialThumbnail
// Display the country name
if let user = item["uploader"] as? PFUser{
item.fetchIfNeeded()
cell.userName!.text = user.username
var profileImgFile = user["profilePicture"] as! PFFile
cell.profileImageView.file = profileImgFile
cell.profileImageView.loadInBackground { image, error in
if error == nil {
cell.profileImageView.image = image
}
}
var sexInt = user["sex"] as! Int
var sex: NSString!
if sexInt == 0 {
sex = "M"
}else if sexInt == 1{
sex = "F"
}
var height = user["height"] as! Int
cell.heightSexLabel.text = "\(sex) \(height)cm"
}
if let votesValue = item["votes"] as? Int
{
cell.votesLabel?.text = "\(votesValue)"
}
// Fetch final flag image - if it exists
if let value = item["imageFile"] as? PFFile {
println("Value \(value)")
cell.postsImageView.file = value
cell.postsImageView.loadInBackground({ (image: UIImage?, error: NSError?) -> Void in
if error != nil {
cell.postsImageView.image = image
}
})
}
return cell
}
I have implemented SDWebImage using Pods and have imported through the Bridging Header. Is there anyone who knows how to implement SDWebImage with parse using Swift?
You should rethink your approach -
I believe you are using collectionViewDelegate method - collectionView(_:cellForItemAtIndexPath:)
this fires every time the collection view needs a view to handle.
In there you can access the cell imageView and set its image (For Example)-
cell.imageView.sd_setImageWithURL(url, placeholderImage:placeHolderImage, completed: { (image, error, cacheType, url) -> Void in })
And if you wish to fade in the image nicely, you could -
cell.imageView.sd_setImageWithURL(url, placeholderImage:placeHolderImage, completed: { (image, error, cacheType, url) -> Void in
if (cacheType == SDImageCacheType.None && image != nil) {
imageView.alpha = 0;
UIView.animateWithDuration(0.0, animations: { () -> Void in
imageView.alpha = 1
})
} else {
imageView.alpha = 1;
}
})
EDIT
I see the you use Parse, so you don't need SDWebImage, you need to use Parse - PFImageView, It will handle your background fetch for the image when it loads. You will need to save reference to your PFObject, but I believe you already do that.
For example (inside your cellForItemAtIndexPath)-
imageView.image = [UIImage imageNamed:#"..."]; // placeholder image
imageView.file = (PFFile *)someObject[#"picture"]; // remote image
[imageView loadInBackground];
How many objects are displaying in the collection view?
Since you mentioned SDWebImage, are you downloading the images in the background as well?
If you want to load the images as the user scrolls, have a look at the documentation for SDWebImage. The first use case describes how to display images in table view cells withouth blocking the main thread. The implementation for collection view cells should be similar.

Receive Image from pointer

I have a pointer in my parse. The pointer tells me who uploaded the images. I am trying to retrieve the username and the profile picture of the uploader. To do that I have put query.includeKey("uploader") . Users are managed through the user class. and posts are managed in the posts class. To retrieve the images and names I have the below code.
func collectionView(collectionView: UICollectionView, cellForItemAtIndexPath indexPath: NSIndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCellWithReuseIdentifier("newview", forIndexPath: indexPath) as! NewCollectionViewCell
let item = self.votes[indexPath.row]
// Display "initial" flag image
var initialThumbnail = UIImage(named: "question")
cell.postsImageView.image = initialThumbnail
if let pointer = item["uploader"] as? PFObject {
cell.userName!.text = item["username"] as? String
}
if let profile = item["uploader"] as? PFObject {
cell.profileImageView.loadInBackground({ (image:UIImage, error:NSError) -> Void in
if error != nil{
cell.profileImageView.image = image
}
})}
if let votesValue = item["votes"] as? Int
{
cell.votesLabel?.text = "\(votesValue)"
}
// Fetch final flag image - if it exists
if let value = item["imageFile"] as? PFFile {
cell.postsImageView.file = value
cell.postsImageView.loadInBackground({ (image: UIImage?, error: NSError?) -> Void in
if error != nil {
cell.postsImageView.image = image
}
})
}
return cell
}
However errors are happening saying that loadinbackround can't be invoked with an argument list of type (UIImage, NSError)->void. The strange part is that the error is only for the first part where I try to retrieve the images for the user. I am really stuck in this and want help. Is my pointer retrieving wrong? Thank you.
UPDATE 2
#IBOutlet weak var collectionView: UICollectionView!
override func viewDidLoad() {
super.viewDidLoad()
let query = PFQuery(className: "Posts")
query.includeKey("pointName")
query.findObjectsInBackgroundWithBlock{(question:[AnyObject]?,error:NSError?) -> Void in
if error == nil
{
if let allQuestion = question as? [PFObject]
{
self.votes = allQuestion
self.collectionView.reloadData()
}
}
}
// Wire up search bar delegate so that we can react to button selections
// Resize size of collection view items in grid so that we achieve 3 boxes across
loadCollectionViewData()
}
/*
==========================================================================================
Ensure data within the collection view is updated when ever it is displayed
==========================================================================================
*/
// Load data into the collectionView when the view appears
override func viewDidAppear(animated: Bool) {
loadCollectionViewData()
}
/*
==========================================================================================
Fetch data from the Parse platform
==========================================================================================
*/
func loadCollectionViewData() {
// Build a parse query object
}
/*
==========================================================================================
UICollectionView protocol required methods
==========================================================================================
*/
func numberOfSectionsInCollectionView(collectionView: UICollectionView) -> Int {
return 1
}
func collectionView(collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return self.votes.count
}
func collectionView(collectionView: UICollectionView, cellForItemAtIndexPath indexPath: NSIndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCellWithReuseIdentifier("newview", forIndexPath: indexPath) as! NewCollectionViewCell
let item = self.votes[indexPath.row]
// Display "initial" flag image
var initialThumbnail = UIImage(named: "question")
cell.postsImageView.image = initialThumbnail
if let pointer = item["uploader"] as? PFObject {
cell.userName!.text = item["username"] as? String
print("username")
}
if let profile = item["uploader"] as? PFObject,
profileImageFile = profile["profilePicture"] as? PFFile {
cell.profileImageView.file = profileImageFile
cell.profileImageView.loadInBackground { image, error in
if error == nil {
cell.profileImageView.image = image
}
}
}
if let votesValue = item["votes"] as? Int
{
cell.votesLabel?.text = "\(votesValue)"
}
// Fetch final flag image - if it exists
if let value = item["imageFile"] as? PFFile {
println("Value \(value)")
cell.postsImageView.file = value
cell.postsImageView.loadInBackground({ (image: UIImage?, error: NSError?) -> Void in
if error != nil {
cell.postsImageView.image = image
}
})
}
return cell
}
In my post class it is like this
The users are managed in the user class. I want to get the profile image and username of the person who posted the image.
In the user class I have all the user information.
cell.postsImageView.loadInBackground({
(image: UIImage!, error: NSError!) -> Void in
if error == nil {
if image != nil {
dispatch_async(dispatch_get_main_queue(),{
cell.postsImageView.image = image
})
}else{
println("Image not available")
}
}else{
println(Image Downloading error: \(error))
}
})
Try this , i think this will help you :)
Try to replace your loadInBackground method with the below:
cell.postsImageView.loadInBackground({ (image: UIImage!, error: NSError!) -> Void in
if error == nil {
cell.postsImageView.file = value
cell.postsImageView.image = image
}
})
}
You have two issues here, the first being the way you pass the closure to the loadInBackground method
The compiler error is because you're trying to call the method with non-optional closure parameters.
In the cell.postsImageView.loadInBackground call you use optionals, while in the cell.profileImageView.loadInBackground you don't.
Closure parameter types are important, that's why the compiler is complaining.
I'd suggest skipping the types and defining the closure like this:
cell.profileImageView.loadInBackground { image, error in
if error != nil{
cell.profileImageView.image = image
}
})}
The other and probably your main issue is that you don't set a file for the profile. So, if we say that the profile image is stored under imageFile in the uploader object, you would use:
if let profile = item["uploader"] as? PFObject,
profileImageFile = profile["imageFile"] as? PFFile {
cell.profileImageView.file = profileImageFile
cell.profileImageView.loadInBackground { image, error in
if error == nil {
cell.profileImageView.image = image
}
}
}
Though, as the Parse documentation says, the method downloads and displays the image:
Once the download completes, the remote image will be displayed.
https://parse.com/docs/ios/api/Classes/PFImageView.html#//api/name/loadInBackground:
If you don't need any special error handling and since you already have a placeholder image, try loading the image like this:
if let profile = item["uploader"] as? PFObject,
profileImageFile = profile["imageFile"] as? PFFile {
cell.profileImageView.file = profileImageFile
cell.profileImageView.loadInBackground()
}

Resources