CollectionView flash when reloadData - ios

I have a collectionView which is populated with around 60 images downloading from parse. These images can be updated depending if any new ones have been uploaded.
But my problem is after I load the view, and I refresh the data using PullToRefresh function, the collection view Flashes white and then displays the images again...
here's a video to show you :
https://www.youtube.com/watch?v=qizaAbUnzYQ&feature=youtu.be
I have been trying to fix this all day & find a solution, but I have had no success..!
Heres how I'm querying the images :
func loadPosts() {
self.activityView.startAnimating()
let followQuery = PFQuery(className: "Follows")
followQuery.whereKey("follower", equalTo: PFUser.currentUser()!.username!)
followQuery.findObjectsInBackgroundWithBlock ({ (objects:[PFObject]?, error:NSError?) -> Void in
if error == nil {
self.followArray.removeAll(keepCapacity: false)
for object in objects! {
self.followArray.append(object.valueForKey("following") as! String)
}
let query = PFQuery(className: "Posts")
query.limit = self.page
query.whereKey("username", notContainedIn: self.followArray)
query.whereKey("username", notEqualTo: PFUser.currentUser()!.username!)
query.findObjectsInBackgroundWithBlock ({ (objects:[PFObject]?, error:NSError?) -> Void in
if error == nil {
self.postImage.removeAll(keepCapacity: false)
self.uuidArray.removeAll(keepCapacity: false)
self.usernameArray.removeAll(keepCapacity: false)
for object in objects! {
self.postImage.append(object.valueForKey("image") as! PFFile)
self.uuidArray.append(object.valueForKey("uuid") as! String)
self.usernameArray.append(object.valueForKey("username") as! String)
}
} else {
print(error!.localizedDescription)
}
self.collectionView.reloadData()
self.refresher.endRefreshing()
self.activityView.stopAnimating()
self.boxView.removeFromSuperview()
})
}
})
}
And here is how I am pulling to refresh:
override func viewDidLoad() {
super.viewDidLoad()
refresher.addTarget(self, action: "reload", forControlEvents: UIControlEvents.ValueChanged)
collectionView.addSubview(refresher)
loadPosts()
}
func reload() {
collectionView.reloadData()
refresher.endRefreshing()
}

I assume that the UUID's are unique for every post, so you can check to see if the count from the previous load is different from the current, then you can see which posts are new, figure out their index path then only reload those index paths. I used sets to determine which id's had been added, which will work assuming you don't want to display the same post twice. There might be a better way of doing it, but in general you need to do something similar to the following:
func loadPosts() {
self.activityView.startAnimating()
let followQuery = PFQuery(className: "Follows")
followQuery.whereKey("follower", equalTo: PFUser.currentUser()!.username!)
followQuery.findObjectsInBackgroundWithBlock ({ (objects:[PFObject]?, error:NSError?) -> Void in
if error == nil {
self.followArray.removeAll(keepCapacity: false)
for object in objects! {
self.followArray.append(object.valueForKey("following") as! String)
}
let query = PFQuery(className: "Posts")
query.limit = self.page
query.whereKey("username", notContainedIn: self.followArray)
query.whereKey("username", notEqualTo: PFUser.currentUser()!.username!)
query.findObjectsInBackgroundWithBlock ({ (objects:[PFObject]?, error:NSError?) -> Void in
if error == nil {
let oldUUIDArray = self.uuidArray
self.postImage.removeAll(keepCapacity: false)
self.uuidArray.removeAll(keepCapacity: false)
self.usernameArray.removeAll(keepCapacity: false)
for object in objects! {
self.postImage.append(object.valueForKey("image") as! PFFile)
self.uuidArray.append(object.valueForKey("uuid") as! String)
self.usernameArray.append(object.valueForKey("username") as! String)
}
let uuidOldSet = Set(oldUUIDArray)
let uuidNewSet = Set(self.uuidArray)
let missingUUIDs = uuidNewSet.subtract(uuidOldSet)
let missingUUIDArray = Array(missingUUIDs)
let missingUUIDIndexPaths = missingUUIDArray.map{NSIndexPath(forItem:self.uuidArray.indexOf($0)!,inSe ction:0)}
let extraUUIDs = uuidOldSet.subtract(uuidNewSet)
let extraUUIDArray = Array(extraUUIDs)
let extraUUIDIndexPaths = extraUUIDArray.map{NSIndexPath(forItem:oldUUIDArray.indexOf($0)!,inSection:0)}
self.collectionView.performBatchUpdates({
if extraUUIDIndexPath != nil {
self.collectionView.deleteItemsAtIndexPaths(extraUUIDIndexPaths)
}
if missingUUIDIndexPaths != nil {self.collectionView.insertItemsAtIndexPaths(missingUUIDIndexPaths)}
}, completion: nil)
} else {
print(error!.localizedDescription)
}
self.refresher.endRefreshing()
self.activityView.stopAnimating()
self.boxView.removeFromSuperview()
})
}
})
}
func reload() {
self.loadPosts()
refresher.endRefreshing()
}

Related

Xcode Parse Query button Delete text and photo from a cell

each cell displays the according comments and photo of the user logged-on. They are loaded with parse.
Now you want to Löschen the button deletes the photo and the comments.
Unfortunately this does not work. Wen I click on the button nothing happens
Unfortunately I understand little of swift and can't get on the solution
The query works, and the app displays the photos and Commons.The query and post code:
override func viewDidLoad() {
super.viewDidLoad()
super.viewDidLoad()
let query = PFQuery(className: "Post")
query.whereKey("username", equalTo: PFUser.current()?.username)
query.findObjectsInBackground(block: { (object, error) in
if let posts = object {
for post in posts{
print(posts)
self.comments.append(post["message"] as! String)
self.imageFile.append(post["imageFile"] as! PFFile)
self.tableView.reloadData()
}
DispatchQueue.main.async {
self.tableView.reloadData()
}
}
})
}
And here of the "delete"function code that I have tried:
#IBAction func remove(_ sender: Any) {
print("Entered remove")
let query = PFQuery(className: "Post")
query.whereKey("username", equalTo: PFUser.current()?.username)
query.findObjectsInBackground(block: { (object, error) in
if let posts = object {
print(posts)
for post in posts{
print(posts)
if let message = post["message"] as? String, let image = post["imageFile"] as? PFFile {
print("message and image read", message, image)
if let messageIndex = self.comments.index(of: message), let imageIndex = self.imageFile.index(of:image) {
self.comments.remove(at: messageIndex)
self.imageFile.remove(at: imageIndex)
}
}
self.tableView.reloadData()
}
DispatchQueue.main.async {
self.tableView.reloadData()
}
}
})
}
The output:
I don't get an error message and nothing is deleted.
Thank you for your help
You do not have access to your current index where and object ids.
So based on that you can remove easy.
The more easy way to implement the delete function is to have an array of objectId for your messages:
self.ids.append(post.objectId)
And when you want to delete it:
let query = PFQuery(className: "Post")
query.whereKey("objectId", equalTo: self.ids.index(of: indexPath.row))
// Make a query in background to only get the object that you want to delete
query.getFirstObjectInBackgroundWithBlock {
(object: PFObject?, error: NSError?) -> Void in
if error != nil || object == nil {
print("The getFirstObject request failed.")
} else if let object = object {
print("Successfully retrieved the object.")
object.deleteInBackground()
}
}
Having different arrays representing the same object is not really good to do. So a better way to handle you problem is have only one array for your post
When you fetch it you can do something like that:
guard let user = PFUser.current() else { return }
let query = PFQuery(className: "Post")
query.whereKey("username", equalTo: user.username)
query.findObjectsInBackground(block: { (posts, error) in
if let posts = posts {
self.posts = posts
}
})
With this way when you want to delete it in the remove function:
if indexPath.row < self.posts.count {
self.posts[indexPath.row].deleteInBackground()
}

PFQuery with live progress

How can I show live progress value when using this query?
Can I just a percent block or anything? How do I implement such thing?
func queryStory(){
self.userFile.removeAll()
self.objID.removeAll()
self.createdAt.removeAll()
let query = PFQuery(className: "myClass")
query.whereKey("isPending", equalTo: false)
query.orderByDescending("createdAt")
query.findObjectsInBackgroundWithBlock { (posts: [PFObject]?, error: NSError?) -> Void in
if (error == nil){
// Success fetching objects
print("Post count:", posts!.count)
for post in posts! {
if let imagefile = post["userFile"] as? PFFile {
self.userFile.append(post["userFile"] as! PFFile)
self.objID.append(post.objectId!)
self.createdAt.append(post.createdAt!)
}
}
dispatch_async(dispatch_get_main_queue()) {
self.collectionView.reloadSections(NSIndexSet(index: 0))
if (self.refreshControlSpin == true){
self.refreshControlSpin = false
self.refreshControl.endRefreshing()
}
}
print("Uploaded files count: ", self.userFile.count)
}
else{
print(error)
}
}
}
To show percent value from 0 to 100, and changes live.

Querying from Parse Classes

I am trying to query the user's from _User class, which I have managed successfully. But what I am trying to do now where I'm having a bit of difficulty, is query another class, Posts, and download the images that match the users downloaded from the first query?!
So I am just trying to assign the images from the Posts class to the correct users from the _User class...It sounds very simple, but it driving me mad!!
Here's my code for the query, I know it's probably not the best way but I'm newish to Swift! But I'm willing to try any tips or recommendations if you have any!
let userQuery = PFQuery(className: "_User")
userQuery.addDescendingOrder("createdAt")
userQuery.findObjectsInBackgroundWithBlock ({
(objects:[PFObject]?, error:NSError?) -> Void in
if error == nil {
self.profilePicArray.removeAll(keepCapacity: false)
self.usernameArray.removeAll(keepCapacity: false)
self.fullnameArray.removeAll(keepCapacity: false)
self.uuidArray.removeAll(keepCapacity: false)
for an object in objects! {
self.profilePicArray.append(object.valueForKey("profilePicture") as! PFFile)
self.usernameArray.append(object.valueForKey("username") as! String)
self.fullnameArray.append(object.valueForKey("firstname") as! String)
self.uuidArray.append(object.valueForKey("uuid") as! String)
}
let imageQuery = PFQuery(className: "Posts")
imageQuery.whereKey("username", containedIn: self.usernameArray)
imageQuery.findObjectsInBackgroundWithBlock({ (objects:[PFObject]?, error:NSError?) -> Void in
if error == nil {
self.lastPicArray.removeAll(keepCapacity: false)
for an object in objects! {
self.lastPicArray.append(object.valueForKey("image") as! PFFile)
}
self.collectionView.reloadData()
} else {
print(error!.localizedDescription)
}
})
} else {
print(error!.localizedDescription)
}
})
The result I am getting at the moment is that: all user's download and also all the posts, but the images are just assigned randomly to each user or all the posts appear for each single user!
Thanks in advance.
New Query
func uu() {
let query = PFQuery(className: "_User")
query.addDescendingOrder("createdAt")
query.includeKey("latestImage")
query.whereKey("username", notEqualTo: PFUser.currentUser()!.username!)
query.findObjectsInBackgroundWithBlock { (object:[PFObject]?, error:NSError?) -> Void in
if error == nil {
for object in object! {
if (object.objectForKey("latestImage") != nil)
{
self.lastPicArray.append(object.objectForKey("latestImage")!.valueForKey("image") as! PFFile)
self.profilePicArray.append(object.valueForKey("profilePicture") as! PFFile)
self.fullnameArray.append(object.valueForKey("firstname") as! String)
self.usernameArr.append(object.valueForKey("username") as! String)
}
}
self.collectionView.reloadData()
print(self.usernameArr)
print(self.lastPicArray)
}
}
}
You should be able to do this with just one query, by using the includeKey function of Parse Queries
Parse Queries
Take your 2nd query, and add something like this:
let imageQuery = PFQuery(className: "Posts")
imageQuery.whereKey("username", containedIn: self.usernameArray)
imageQuery.includeKey("fieldNameOfUserPointer")
Just change the 'fieldNameOfUserPointer' to the field name that references your _User object in the Posts entity.

iOS Swift appending value to array

My Question is very simple,
I'm Learning iOS development and I'm stuck with tableviewcontroller
I can add Values to tableview with array, but when I try to append value from Parse, it's not working.
Here is the code:
var names: [String] = ["Name_one", "Name_two"]
let query: PFQuery! = PFUser.query()
override func viewDidLoad() {
super.viewDidLoad()
query.whereKey("objectId", notEqualTo: PFUser.currentUser()!.objectId!)
query.findObjectsInBackgroundWithBlock { objects, error in
if (error == nil) {
for user: PFUser in (objects as! [PFUser]) {
self.names.append(user.username as! String)
}
} else {
print("Error")
}
}
Screen Shot Attachment
You must to reload your tableview after get data finished
Code:
query.findObjectsInBackgroundWithBlock { objects, error in
if (error == nil) {
for user: PFUser in (objects as! [PFUser]) {
self.names.append(user.username as! String)
}
yourTableview.reloadData()
} else {
print("Error")
}
}

Why do i get 0 pinned objects when i query LocalDatastore? iOS. Swift. Parse v1.7.5

func queryForPhotosFromLocalDatastore()
{
var xquery = PFQuery(className: "Follows")
xquery.fromLocalDatastore()
//xquery.whereKey("Follower", equalTo: PFUser.currentUser()!.objectId!)
xquery.findObjectsInBackgroundWithBlock { (objects, error) -> Void in
if let xobjects = objects
{
if xobjects.count > 0
{
for yobject in xobjects
{
println("Done")
}
}
else
{
println("number of objects is \(xobjects.count)")
}
}
else
{
println(error?.userInfo)
}
}
}
func queryForPhotosFromParse()
{
PFObject.unpinAllObjectsInBackgroundWithBlock(nil)
var xquery = PFQuery(className: "Follows")
xquery.whereKey("Follower", equalTo: PFUser.currentUser()!.objectId!)
xquery.findObjectsInBackgroundWithBlock { (objects, error) -> Void in
if let xobjects = objects
{
println("xobjects are \(xobjects.count)")
println("querying from parse")
for yobject in xobjects
{
var followedUser = yobject["Following"] as! String
var query = PFQuery(className: "Images")
query.whereKey("userID", equalTo: followedUser)
query.orderByDescending("createdAt")
query.findObjectsInBackgroundWithBlock { (xobjects, error) -> Void in
if let objects = xobjects
{
PFObject.pinAllInBackground(objects, block: { (success, error) -> Void in
if error == nil
{
println("Pinned \(objects.count) objects")
self.queryForPhotosFromLocalDatastore()
}
})
}
else
{
println(error?.userInfo)
}
}
}
}
}
}
// The number of objects its returning (xobjects.count) is 0. Why is that so ?
I tried to have query localdatastore in my app but The number of objects its returning (xobjects.count) is 0. Why is that so ?
i have tried to query before with the previous versions but same thing happened. The latest version on parse says that they have fixed the error but I'm still getting the number of objects retrieved from localdatastore as "0". Please Help.

Resources