How do I retrieve data by using the Parse PFQuery? - swift

Hi I'm trying to retrive data by using the PFQuery.
loadPosts in the tabelviewController.
My problem is commentsArray.
As you can see... commentsArray is not synchronized other arryas.
Because It has different db's class.
I want get all the data arrays to set the uilabel's text synchronizing
How do I achieve that?
I also had trying to parse's synchronized method. but It is really slow.
Here is my code. This function in the TableViewController.
func loadPosts() {
//STEP 1. Find posts related to people who we are following
let followQuery = PFQuery(className: "fans")
followQuery.whereKey("myfans", equalTo: PFUser.currentUser()!.username!)
followQuery.findObjectsInBackgroundWithBlock ({ (objects:[PFObject]?, error:NSError?) -> Void in
if error == nil {
//clean up
self.followArray.removeAll(keepCapacity: false)
//Appending where people following..
//find related objects
for object in objects! {
self.followArray.append(object.objectForKey("fan") as! String)
}
//append current user to see own posts in feed
self.followArray.append(PFUser.currentUser()!.username!)
//STEP 2. Find posts made by people appended to followArray
let query = PFQuery(className: "posts")
query.whereKey("username", containedIn: self.followArray)
query.limit = self.page
query.addDescendingOrder("createdAt")
query.findObjectsInBackgroundWithBlock({ (objects:[PFObject]?, error:NSError?) -> Void in
if error == nil {
//clean up
self.usernameArray.removeAll(keepCapacity: false)
self.profileArray.removeAll(keepCapacity: false)
self.dateArray.removeAll(keepCapacity: false)
self.postArray.removeAll(keepCapacity: false)
self.descriptionArray.removeAll(keepCapacity: false)
self.uuidArray.removeAll(keepCapacity: false)
//For Test
self.commentsArray.removeAll(keepCapacity: false)
self.isTappedLikeArray.removeAll(keepCapacity: false)
//find related objects
for object in objects! {
self.usernameArray.append(object.objectForKey("username") as! String)
self.profileArray.append(object.objectForKey("profileImg") as! PFFile)
self.dateArray.append(object.createdAt)
self.postArray.append(object.objectForKey("postImg") as! PFFile)
self.descriptionArray.append(object.objectForKey("title") as! String)
self.uuidArray.append(object.objectForKey("uuid") as! String)
//STEP 3.
//Check Comment
let countQuery = PFQuery(className: "comments")
countQuery.whereKey("to", equalTo: object.objectForKey("uuid") as! String)
countQuery.limit = 1
countQuery.addAscendingOrder("createdAt")
countQuery.countObjectsInBackgroundWithBlock({(count:Int32, error:NSError?) -> Void in
//if no any likes are found, else found likes
if count==0 {
self.commentsArray.append("")
}else{
let commentQuery = PFQuery(className: "comments")
commentQuery.whereKey("to", equalTo: object.objectForKey("uuid") as! String)
commentQuery.limit = 1
commentQuery.addDescendingOrder("createdAt")
commentQuery.findObjectsInBackgroundWithBlock({(objects:[PFObject]?, error:NSError?) -> Void in
if error == nil {
//clean up
//find related object
for object in objects!{
let comment = object.objectForKey("comment") as! String
let by = object.objectForKey("username") as! String
let commentString = by + " " + comment
self.commentsArray.append(commentString)
}
//reload tableView & end spinning of refresher
self.tableView.reloadData()
self.refresher.endRefreshing()
}else {
print(error?.localizedDescription)
}
})
}
})
}
} else {
print(error!.localizedDescription)
}
})
} else {
print(error!.localizedDescription)
}
})
}

Related

Parse query in Swift - Can't seem to sort the query from newest to oldest

self.messageFromId.removeAll()
self.messageFrom.removeAll()
self.taskTitle.removeAll()
self.message.removeAll()
self.taskId.removeAll()
self.messageId.removeAll()
self.messageType.removeAll()
if PFUser.current()?.objectId! != nil {
let query = PFQuery(className: "Message")
query.addDescendingOrder("createdAt")
query.limit = 10
cur = PFUser.current()!.objectId!
query.whereKey("messageTo", equalTo: cur!)
query.findObjectsInBackground(block: { (objects, error) in
if let posts = objects{
for object in posts {
if let post = object as? PFObject {
let query2 = PFUser.query()
query2?.whereKey("objectId", equalTo: post["messageFrom"] as! String)
query2?.findObjectsInBackground(block: { (objects, error) in
if let posts = objects{
for object in posts {
if let post2 = object as? PFObject {
if post2["handle"] as! String == "new$!" {
self.messageFromId.append(post["messageFrom"] as! String)
self.messageFrom.append(post["messageFrom"] as! String)
self.taskTitle.append(post["taskTitle"] as! String)
self.message.append(post["message"] as! String)
self.taskId.append(post["taskId"] as! String)
self.messageId.append(post.objectId!)
self.messageType.append(post["messageType"] as! String)
} else {
self.messageFromId.append(post["messageFrom"] as! String)
self.messageFrom.append(post2["handle"] as! String)
self.taskTitle.append(post["taskTitle"] as! String)
self.message.append(post["message"] as! String)
self.taskId.append(post["taskId"] as! String)
self.messageId.append(post.objectId!)
self.messageType.append(post["messageType"] as! String)
}
}
}
}
self.tableView.reloadData()
self.refresher.endRefreshing()
})
}
}
}
})
}
Results seems to come back in a random order, not sure why ? Am I doing the query within the query correctly ?
I did add : query.addDescendingOrder("createdAt") at the beginning of the query. It's not working
Try using: query.order(byDescending: "createdAt") instead.

How do I change data model?

I'm making an social media apps.
user
- displayname
- username
- profileImg
- password
- email
comments
- username
- comment
- to
friends
- follower
- following
hashtags
- hashtag
- to
- by
- comment
likes
- to
- by
posts
- postImg
- username
- title
- uuid
My question is when USERS post the image with title text then
I want retrieve username, profileImg, title, comment, commentby, postImg, count of likes
My approach is redesign the posts db
posts
- postImg
- username
- title
- uuid
- comment
- commentby
- profileImg
- count of likes
But I think it is poor design of db.
func loadPosts() {
//STEP 1. Find posts related to people who we are following
let followQuery = PFQuery(className: “friends")
followQuery.whereKey(“following", equalTo: PFUser.current()!.username!)
followQuery.findObjectsInBackground (block: { (objects:[PFObject]?, error:Error?) -> Void in
if error == nil {
//clean up
self.followArray.removeAll(keepingCapacity: false)
//Appending where people following..
//find related objects
for object in objects! {
self.followArray.append(object.object(forKey: “following") as! String)
}
//append current user to see own posts in feed
self.followArray.append(PFUser.current()!.username!)
//STEP 2. Find posts made by people appended to followArray
let query = PFQuery(className: "posts")
query.whereKey("username", containedIn: self.followArray)
query.limit = self.page
query.addDescendingOrder("createdAt")
query.findObjectsInBackground(block: { (objects:[PFObject]?, error:Error?) -> Void in
if error == nil {
//clean up
self.usernameArray.removeAll(keepingCapacity: false)
// self.profileArray.removeAll(keepCapacity: false)
self.dateArray.removeAll(keepingCapacity: false)
self.postArray.removeAll(keepingCapacity: false)
self.descriptionArray.removeAll(keepingCapacity: false)
self.uuidArray.removeAll(keepingCapacity: false)
self.commentsArray.removeAll(keepingCapacity: false)
self.commentsByArray.removeAll(keepingCapacity: false)
//find related objects
for object in objects! {
self.usernameArray.append(object.object(forKey: "username") as! String)
// self.profileArray.append(object.objectForKey("profileImg") as! PFFile)
self.dateArray.append(object.createdAt)
self.postArray.append(object.object(forKey: "postImg") as! PFFile)
self.descriptionArray.append(object.object(forKey: "title") as! String)
self.uuidArray.append(object.object(forKey: "uuid") as! String)
//set Comments
let comment = object.object(forKey: "comment") as! String
let by = object.object(forKey: "commentby") as! String
let commentString = " " + comment
self.commentsByArray.append(by)
self.commentsArray.append(commentString)
}
//reload tableView & end spinning of refresher
self.tableView.reloadData()
self.refresher.endRefreshing()
} else {
print(error!.localizedDescription)
}
})
} else {
print(error!.localizedDescription)
}
})
}
defined cell
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
//define cell
let cell = tableView.dequeueReusableCell(withIdentifier: "ShopDetailCell", for: indexPath) as! ShopDetailCell
cell.userNameLabel.text = usernameArray[(indexPath as NSIndexPath).row - 1]
cell.userNameLabel.sizeToFit()
cell.uuidLabel.text = uuidArray[(indexPath as NSIndexPath).row - 1]
cell.descriptionLabel.text = descriptionArray[indexPath.row - 1]
cell.descriptionLabel.sizeToFit()
cell.commentLabel.sizeToFit()
//Load ProfileImage
let profileImgQuery = PFQuery(className: "_User")
profileImgQuery.whereKey("username", equalTo: usernameArray[(indexPath as NSIndexPath).row - 1])
profileImgQuery.findObjectsInBackground(block: {(objects:[PFObject]?, error:Error?) -> Void in
if error == nil {
//shown wrong user
if objects!.isEmpty {
print("Wrong User")
}
//find related to user information
for object in objects! {
//Set Image
let profilePictureObject = object.object(forKey: "profileImg") as? PFFile
profilePictureObject?.getDataInBackground { (imageData:Data?, error:Error?) -> Void in
if(imageData != nil)
{
let profileURL : URL = URL(string: profilePictureObject!.url!)!
cell.userImg.sd_setImage(with: profileURL, placeholderImage: UIImage(named: "holderImg"))
}
}
}
} else {
print(error?.localizedDescription)
}
})
//Clip to circle
cell.userImg.layoutIfNeeded()
cell.userImg.layer.cornerRadius = cell.userImg.frame.size.width/2
cell.userImg.clipsToBounds = true
// place post picture using the sdwebimage
let postURL : URL = URL(string: postArray[(indexPath as NSIndexPath).row - 1].url!)!
cell.postImg.sd_setImage(with: postURL, placeholderImage: UIImage(named: "holderImg"))
//Calculate post date
let from = dateArray[(indexPath as NSIndexPath).row - 1]
let now = Date()
let components : NSCalendar.Unit = [.second, .minute, .hour, .day, .weekOfMonth]
let difference = (Calendar.current as NSCalendar).components(components, from: from!, to: now, options: [])
// logic what to show : Seconds, minutes, hours, days, or weeks
if difference.second! <= 0 {
cell.dateLabel.text = "NOW"
}
if difference.second! > 0 && difference.minute! == 0 {
cell.dateLabel.text = "\(difference.second!) SEC AGO"
}
if difference.minute! > 0 && difference.hour! == 0 {
cell.dateLabel.text = "\(difference.minute!) MIN AGO"
}
if difference.hour! > 0 && difference.day! == 0 {
cell.dateLabel.text = "\(difference.hour!) HR AGO"
}
if difference.day! > 0 && difference.weekOfMonth! == 0 {
cell.dateLabel.text = "\(difference.day!) DAY AGO"
}
if difference.weekOfMonth! > 0 {
cell.dateLabel.text = "\(difference.weekOfMonth!) WEEK AGO"
}
cell.dateLabel.sizeToFit()
//Set Text Label
if cell.descriptionLabel.text!.isEmpty == true || cell.descriptionLabel.text == " "{
if cell.commentLabel.text!.isEmpty == true || cell.commentLabel.text == " "{
cell.dateTop.constant = 7
}else {
cell.dateTop.constant = cell.commentTop.constant + cell.commentLabel.frame.height + 8
}
}else {
if cell.commentLabel.text!.isEmpty == true || cell.commentLabel.text == " "{
cell.dateTop.constant = cell.descriptionTop.constant + cell.descriptionLabel.frame.height + 8
}else {
cell.commentTop.constant = cell.descriptionTop.constant + cell.descriptionLabel.frame.height + 8
cell.dateTop.constant = cell.commentTop.constant + cell.commentLabel.frame.height + 8
}
}
// manipulate like button depending on did user like it or not
let didLike = PFQuery(className: "likes")
didLike.whereKey("by", equalTo: PFUser.current()!.username!)
didLike.whereKey("to", equalTo: cell.uuidLabel.text!)
didLike.countObjectsInBackground(block: {(count:Int32, error:Error?) -> Void in
//if no any likes are found, else found likes
if count==0 {
cell.likeBtn.setTitle("unlike", for: UIControlState())
cell.likeBtn.setImage(UIImage(named:"heartBtn"), for: UIControlState())
}else{
cell.likeBtn.setTitle("like", for: UIControlState())
cell.likeBtn.setImage(UIImage(named: "heartTapBtn"), for: UIControlState())
}
})
//count total likes of shown post
let countLikes = PFQuery(className: "likes")
countLikes.whereKey("to", equalTo: cell.uuidLabel.text!)
countLikes.countObjectsInBackground(block: {(count:Int32, error:Error?) -> Void in
cell.likesLabel.text="\(count) likes"
})
cell.userNameLabel.layer.setValue(indexPath, forKey: "index")
cell.commentBtn.layer.setValue(indexPath, forKey: "index")
cell.moreBtn.layer.setValue(indexPath, forKey: "index")
return cell
}
Could you anyone advising me?
I had read this tutorial "https://parse.com/tutorials/anypic" but I can't decided which data model is better for me
I wish to uses join or pointer method.
You can save the currentUser as a pointer in your Posts class whenever a user makes a post.
note: I will demonstrate in Objective-C but it's very easy for you to translate into Swift. But if you have trouble reading objc code, I will edit my answer to Swift version.
func post { //make a post
var post = PFObject(className:"Posts")
post["user"] = PFUser.current()//save the current user as a pointer pointing to the User class. You can add a column of type pointer in your parse dashboard inside your Posts class.
//set up other attributes here...
post.saveInBackground()
}
Then when we do the query, we can use includeKey to include the user pointer.
let query = PFQuery(className: "posts")
query.whereKey("username", containedIn: self.followArray)
query.includeKey("user")// THIS IS IMPORTANT
query.limit = self.page
query.addDescendingOrder("createdAt")
query.findObjectsInBackground(block: { (objects:[PFObject]?, error:Error?) -> Void in
if !error {
//we can access the user pointer by doing:
for object in objects {
var user = object["user"]
var username = user.username
var profileImage = user["profileImg"] //a PFFile
//...
}
}
Besides, you can always use a PFQueryTableViewController to load the objects for you, so you don't need to store the query results manually.

Parse data in swift

I have a "Users" table and a "cDetails" table. Inside cDetails table I have a field called "full_name". I am trying to retrieve and output the value in this table based on the current user that is logged in.
In the cDetails table I have a field called "createdBy" which points to the objectID in the Users table that created it.
This is all I have so far:
let query = PFQuery(className: "cDetails")
let currentUser = PFUser.currentUser()
query.includeKey("full_name")
query.whereKey("createdBy", equalTo: currentUser!.objectId!)
print("CREATED BY " + PFUser.currentUser()!.objectId!);
query.findObjectsInBackgroundWithBlock {
(objects, error) -> Void in
if objects == nil {
print(objects)
print("called")
// self.full_nameLabel.text = "\(query)"
} else {
print("FAILED")
}
}
My approach:
let query = PFQuery(className: "cDetails")
let currentUser = PFUser.currentUser()
query.includeKey("full_name")
query.whereKey("createdBy", equalTo: currentUser!.objectId!)
print("CREATED BY " + PFUser.currentUser()!.objectId!);
query.findObjectsInBackgroundWithBlock {
(objects, error) -> Void in
if **objects == nil** {
print(objects)
print("called")
// self.full_nameLabel.text = "\(query)"
} else {
print("FAILED")
}
}
You are looking whether objects == nil. You want to have your error == nil and your objects != nil
After that proceed with
for object in objects {
let fullName = object["full_name"] as! String
}

Array out of index when getting PFFile from Parse

My app gets the images just fine but if I scroll up and down for a while and then pull to refresh, it crashes and says array out of index. This does not happen every time. I believe it has something to do with the fact that I am not using getdatainbackground but when I go to use that instead of getData(), it loops faster than it can actually retrieve the files and they are out of order.
My current code also gives me this error: Break on warnBlockingOperationOnMainThread() to debug.
2016-03-02 00:35:48.630 App Name[1137:96655] Warning: A long-running operation is being executed on the main thread.
if Reachability.isConnectedToNetwork() {
self.skip = 0
//--RESETTING THE ARRAYS FOR DATA--\\
self.contactText.removeAll(keepCapacity: true)
self.names.removeAll(keepCapacity: true)
self.images.removeAll(keepCapacity: true)
self.prices.removeAll(keepCapacity: true)
self.sizes.removeAll(keepCapacity: true)
self.conditions.removeAll(keepCapacity: true)
self.dates.removeAll(keepCapacity: true)
self.ids.removeAll(keepCapacity: true)
self.createdBy.removeAll(keepCapacity: true)
//--RESET THE USERS LOCATION WHEN HE REFRESHES IN CASE OF A DARASTIC MOVE IN LOCATION--\\
let userGeoPoint = PFUser.currentUser()!["location"] as! PFGeoPoint
//--GETTING ALL OF THE OBJECTS WITHIN 60 MILES OF USERS CURRENT LOCATION--\\
let query = PFQuery(className:"Shoes")
query.whereKey("Location", nearGeoPoint: userGeoPoint, withinMiles: 60)
let user = PFUser.currentUser() as PFUser!
let array: AnyObject? = user["blockedUsers"]
if(array != nil){
query.whereKey("createdBy", notContainedIn: array! as! [AnyObject])
}
query.limit = 50
query.orderByDescending("createdAt")
query.skip = self.skip
query.findObjectsInBackgroundWithBlock {
(objects: [AnyObject]?, error: NSError?) -> Void in
if error == nil {
print("Successfully retrieved \(objects!.count) scores.")
for object in objects! {
if let dateCreated = object.createdAt as NSDate? {
self.dates.append(dateCreated)
}
self.contactText.append(object["Contact"] as! String)
self.descriptions.append(object["Description"] as! String)
self.names.append(object["Name"] as! String)
if object["price"] as! String == "" || object["price"] == nil{
self.prices.append("Negotiable")
}else{
self.prices.append(object["price"] as! String)
}
if object["size"] as! String == "" || object["size"] == nil{
self.sizes.append("N/A")
}else{
self.sizes.append(object["size"] as! String)
}
if object["conditionType"] as! String == "" || object["conditionType"] == nil{
self.conditions.append("N/A")
}else{
self.conditions.append(object["conditionType"] as! String)
}
self.ids.append(object.valueForKey("objectId") as! String)
self.createdBy.append(object["createdBy"] as! String)
let imageFile = object["imageFile"] as! PFFile
let imageData = imageFile.getData()
if (imageData != nil) {
let image = UIImage(data:imageData!)
self.images.append(image!)
}
}
dispatch_async(dispatch_get_main_queue(), {
self.tableView.reloadData()
})
}
else {
print(error)
}
self.refresher.endRefreshing()
}
self.skip+=50
} else {
print("Internet connection not available")
self.refresher.endRefreshing()
let alert = UIAlertView(title: "No Internet connection", message: "Please ensure you are connected to the Internet", delegate: nil, cancelButtonTitle: "OK")
alert.show()
}
Try adding a check to make sure your arrays aren't empty when assigning data to cells.

How to have a nest queries in Parse in Swift

I'm facing an issue with Parse.
I have three classes : Users, Posts, Likes
I'm using pointers for the Likes class User pointing to Users Class, and Post pointing to Posts class.
I'm retrieving all the posts and then I would like to see if the current user likes a post or not, and for that I'm nesting a query. the problem I have is that the posts are not updated with the like boolean value. I'm using that code :
func loaddata(limit:Int, skip:Int) {
MainFunctions.getphones{(phones) -> Void in
var indxesPath:[NSIndexPath] = [NSIndexPath]()
let query = PFQuery(className: "Feed")
query.whereKey("username", containedIn: phones)
query.limit = limit
query.skip = skip
query.includeKey("from")
query.addDescendingOrder("createdAt")
query.findObjectsInBackgroundWithBlock {
(objects: [PFObject]?, error: NSError?) -> Void in
if error == nil {
if let objects = objects {
if objects.isEmpty {
}
else {
for object in objects {
let Date = object.createdAt
let post = Post(time: Date!)
let Type = object.objectForKey("type") as? String
post.Post = object
post.Post_message = object.objectForKey("Text") as? String
post.comments = object.objectForKey("commentaires") as? Int
post.likes = object.objectForKey("likes") as? Int
// See if the current user likes a post
let query_like = PFQuery(className:"Likes")
query_like.whereKey("Post", equalTo: object)
query_like.whereKey("User", equalTo: PFUser.currentUser()!)
query_like.getFirstObjectInBackgroundWithBlock{
(like: PFObject?, error: NSError?) -> Void in
if error == nil && like != nil {
post.DoILike = true
} else {
post.DoILike = false
}
}
self.posts.append(post)
indxesPath.append(NSIndexPath(forRow: self.posts.count - 1, inSection: 0))
}
self.tableView.beginUpdates()
self.tableView.insertRowsAtIndexPaths(indxesPath, withRowAnimation: UITableViewRowAnimation.Bottom)
self.tableView.endUpdates()
self.tableView.finishInfiniteScroll()
self.refreshControl.endRefreshing()
}
}
} else {
self.tableView.finishInfiniteScroll()
self.refreshControl.endRefreshing()
}
}
}
}
query_like.getFirstObjectInBackgroundWithBlock is asynchrone so when you are adding the post to the posts array self.posts.append(post) post.DoILike will get it's default value. So make sure when appending post to posts you have already get if the user liked the post or not.