Retrieving Parse Images Are Out of Order Swift - ios

I am writing an application in Swift that uses Parse for its backend. The user can post images to parse and they are displayed in a collectionView when the user logs in.
The new problem I am having is when retrieving all of my images from parse for the current user, the images are displayed all out of order. Actually, just about every time the images are retrieved they are in a slightly different order. I tried looking at other posts where people had this problem but they didn't seem to do the trick.
Here is my code to retrieve all image posts by a user (the current user):
func retrieveAllImagesForUserId(userId:String){
self.arrayOfUserPosts.removeAll()
let query = PFQuery(className: "ImagePost")
query.whereKey("UserId", equalTo: userId)
query.orderByDescending("createdAt")
query.findObjectsInBackgroundWithBlock {
(object:[PFObject]?, error:NSError?) -> Void in
if ( error != nil ){
print(error?.localizedDescription, error?.userInfo)
} else {
for temp: PFObject in object! {
let username: String = temp["Username"] as! String
let userId: String = temp["UserId"] as! String
let description: String = temp["ImageDescription"] as! String
let imageId: String = temp.objectId!
let file: PFFile = temp["Image"] as! PFFile
file.getDataInBackgroundWithBlock {
(imageData: NSData?, error: NSError?) -> Void in
if error == nil {
if let imageData = imageData {
let retrievedImage = UIImage(data: imageData)
self.imagePost = ImagePost.init(
image: retrievedImage!,
userId: userId,
imageId: imageId,
description: description,
username: username)
self.arrayOfUserPosts.append(self.imagePost!)
NSNotificationCenter.defaultCenter().postNotificationName("retrievedPost", object: nil)
}
}
}
}
}
}
}
The first thing i did was remove all objects to avoid any possible duplications to occur, maybe from a previous user who was logged on to the same device or anything like that.
For every image posted, i am also posting a column which has the users objectId whom posted that image. This way, i can query where said key is equal to the current users objectId.
I am doing an additional query to orderByDescending("createdAt") so the new images will be displayed at the top of my collection view.
My ImagePost class is an extremely simple class that is used for populating the area with objects, it looks like this:
class ImagePost {
var postedImage: UIImage?
var userId: String?
var imageId: String?
var description: String?
var username: String?
init(image:UIImage, userId:String, imageId:String, description: String, username: String ) {
self.postedImage = image
self.userId = userId
self.imageId = imageId
self.description = description
self.username = username
}
}
When the data is retrieved, i append the new ImagePost object to my array, which is the array i used to populate my collectionView and send a notification to reload the collection view.
I just really don't understand why I am having this problem so all of a sudden where the images are being retrieved in almost any order they choose. Any help would be greatly appreciated.
If you know the solution in objective-c but not swift that will also be helpful.
Thank you,
Rob

I had integrated something similar using Parse.
You don't need to fetch all the images at first. You can use a third party library SDWebImageCache for downloading the image when needed or caching.
Have the postedImage type as PFFile and assign the imageFile directly. No need of fetching the imageData.
Have another key called updatedAt in ImagePost class. No need of using predicate when querying the objects from Parse. Save the updatedAt time of ImagePost class. So now you can directly append the data to arrayOfUserPosts.
After completion of the loop, you can sort the array and assign it to self.arrayOfUserPosts.
Then in tableView's dataSource tableView:cellForRowAtIndexPath: method, you can do something like,
[cell.imageView sd_setImageWithURL:[NSURL URLWithString:file.url] placeholderImage:nil completed:^(UIImage *image, NSError *error, SDImageCacheType cacheType, NSURL *imageURL) {
// Any custom view initialisation if needed.
}
where imageView is your display view for image, file is the object of type PFFile which represent the image. This is a Objective-C code. Similar syntax for Swift.

Related

How to get ObjectID and search for specific ObjectID in CoreData in Swift 5?

I am currently working on a project with a multi user system. The user is able to create new profiles which are saved persistently using CoreData.
My problem is: Only one profile can be the active one at a single time, so I would like to get the ObjectID of the created profile and save it to UserDefaults.
Further I was thinking that as soon as I need the data of the active profile, I can simply get the ObjectID from UserDefaults and execute a READ - Request which only gives me back the result with that specific ObjectID.
My code so far for SAVING THE DATA:
// 1. Create new profile entry to the context.
let newProfile = Profiles(context: context)
newProfile.idProfileImage = idProfileImage
newProfile.timeCreated = Date()
newProfile.gender = gender
newProfile.name = name
newProfile.age = age
newProfile.weight = weight
// 2. Save the Object ID to User Defaults for "activeUser".
// ???????????????????
// ???????????????????
// 3. Try to save the new profile by saving the context to the persistent container.
do {
try context.save()
} catch {
print("Error saving context \(error)")
}
My code so far for READING THE DATA
// 1. Creates an request that is just pulling all the data.
let request: NSFetchRequest<Profiles> = Profiles.fetchRequest()
// 2. Try to fetch the request, can throw an error.
do {
let result = try context.fetch(request)
} catch {
print("Error reading data \(error)")
}
As you can see, I haven't been able to implement Part 2 of the first code block. The new profile gets saved but the ObjectID isn't saved to UserDefaults.
Also Party 1 of the second code block is not the final goal. The request just gives you back all the data of that entity, not only the one with the ObjectID I stored in User Defaults.
I hope you guys have an idea on how to solve this problem.
Thanks for your help in advance guys!
Since NSManagedObjectID does not conform to one of the types handled by UserDefaults, you'll have to use another way to represent the object id. Luckily, NSManagedObjectID has a uriRepresentation() that returns a URL, which can be stored in UserDefaults.
Assuming you are using a NSPersistentContainer, here's an extension that will handle the storage and retrieval of a active user Profile:
extension NSPersistentContainer {
private var managedObjectIDKey: String {
return "ActiveUserObjectID"
}
var activeUser: Profile? {
get {
guard let url = UserDefaults.standard.url(forKey: managedObjectIDKey) else {
return nil
}
guard let managedObjectID = persistentStoreCoordinator.managedObjectID(forURIRepresentation: url) else {
return nil
}
return viewContext.object(with: managedObjectID) as? Profile
}
set {
guard let newValue = newValue else {
UserDefaults.standard.removeObject(forKey: managedObjectIDKey)
return
}
UserDefaults.standard.set(newValue.objectID.uriRepresentation(), forKey: managedObjectIDKey)
}
}
}
This uses a method on NSPersistentStoreCoordinator to construct a NSManagedObjectID from a URI representation.

Struggling to append arrays across Parse classes

Hi guys I'm trying to build a simple swipe app to like and dislike uploaded photos. I'm struggling with adding the likes/dislikes to Parse the way that I want them to. I've tried two ways so far:
adding the objectId of the posted image to the User who liked/disliked it but the problem is only one of the objectId's shows up in the array.
staying in the Parse class where the images are posted to (Post), add the userID of the liker/disliker to the image. This doesn't happen at all, new rows are created with new objectId's everytime an image is liked/disliked.
Ideally I want the users who have liked/disliked the photo in a single array so I can query this later. I don't have a great understanding of Parse, it's my first time using it so any help will be massively appreciated.
Here is the code I'm using when an image is swiped (adding to Post class):
if gesture.state == UIGestureRecognizerState.Ended {
var likedOrDisliked = ""
if label.center.x < 100 {
print("Dislike")
likedOrDisliked = "disliked"
} else if label.center.x > self.view.bounds.width - 100 {
print("Like")
likedOrDisliked = "liked"
}
if likedOrDisliked != ""{
var post = PFObject(className: "Post")
post.addUniqueObjectsFromArray([(PFUser.currentUser()?.objectId!)!], forKey: likedOrDisliked)
post.saveInBackground()
}
This is the snippet of when I try adding to User class:
PFUser.currentUser()?.addUniqueObjectsFromArray([displayedUserID], forKey: likedOrDisliked)
do {
try PFUser.currentUser()?.save()
} catch {
}
Here is what happens in the dashboard,
new rows created
What you wanted is to update the actual Post with the like/dislike user
Create a Post (This part you have not explained but i am show a simple assumption - pseuodo code)
var post = PFObject(class:"Post")
post["image"] = PFFile(image)
post.save()
Next you show the image on screen by getting the image from the post
When the user dislikes/likes
you add the current PFUser to the liked/disliked column and save back the object.
let arrayMut = NSMutableArray()
var array = NSArray()
if let arrayData = post.objectForKey("likedUser") as? NSArray {
array = arrayData
}
loop through now the array to find if current user is there.. if not find .. add current PFUser
arrayMut.addObject(PFUser.currentUser().objectId);
post.setObject(arrayMut, forKey: "likedUser")
post.save()
I've tried a lot of things and eventually something stuck, the desired effect was achieved through (added the current user to the liked or disliked fields) :
if likedOrDisliked != ""{
var post = PFQuery(className: "Post")
post.findObjectsInBackgroundWithBlock({ (objects: [PFObject]?, error: NSError?) -> Void in
if error == nil {
if let objects = objects {
for object in objects {
var objId = object["objectId"]
var query = PFQuery(className: "Post")
query.findObjectsInBackgroundWithBlock({ (objects, error) -> Void in
if error == nil {
object.addUniqueObjectsFromArray([(PFUser.currentUser()?.objectId)!], forKey: likedOrDisliked)
object.saveInBackground()
}
})
}
}
}
})

Does parse PFUser download all User object columns content?

I have a User class in Parse that contains a profilePicture along with some other User info. I couldn't figure out if when I run a query in Swift and Parse returns the PFUser object, does that object already contain the profilePicture or does it download it when I use
PFUser.currentUser()?["profilePicture"]
The object only contain the profilePicture as a PFFile (PFFile representes a file of binary data stored on the Parse servers). You are simply accessing the PFFile which is by indexing with ["profilePicture"].
To get the actual profilePicture when you use it, you can do something like the following to turn the PFFile into UIImage and display it out.
let imageFile = listingObjectPassed["imageFile"] as! PFFile
imageFile.getDataInBackgroundWithBlock { (data, error) -> Void in
if let downloadedImage = UIImage(data: data!) {
self.imagePic.image = downloadedImage
}
}

Can't retrieve a picture to swift from parse.com using their documentation

I have been trying to follow parse.com's intruction to retrieve a picture I already successfully uploaded (also using their documentation). My code:
let testObject = PFObject(className: "TestObject")
let file = testObject["SampleImage.png"] as PFFile
file.getDataInBackgroundWithBlock {
(imageData: NSData?, error: NSError?) -> Void in
if error == nil {
if let imageData = imageData {
let image = UIImage(data:imageData)
self.mainImg.image = image
print("Image Retreived")
I am getting the error:
"AnyObject! is not convertible to 'PFFile'"
and then it sugests that I include a ! in 'as'. However, when I do, the application runs but does not retrieve anything.
I realize this question is posted elsewhere, but the answer is not working for me. What am I doing wrong?
let testObject = PFObject(className: "TestObject")
This is a new empty object which isn't backed by anything on the server. You need to set the id to a known value and refresh the instance of you need to run a query to find an object before the resulting object will contain anything.

Entering Zip Code Switchies View Controller If Found In Parse (Swift and XCode)

So I'm trying to create a registration page with availability by Zip Code.
For instance, a user can only register if the service is available in their area (zip code).
So far I have a Text field for Zip Code and a button labeled "Check Availability".
I have a Parse Backend and I tested a connection to it using their setup guide and it works.
How can I go about adding Zip Codes to Parse and when a user types in that zip code that matches it'll open a new View Controller and they can register.
First method is to save zipCode that the user entered from the TextField:
var zipcodeFromUsers = customTextfield.text.toInt()
var savingObject = PFObject(className: "nameoftheclass")
savingObject["username"] = PFUser.currentUser()?.username
savingObject["zipcode"] = zipcodeFromUsers
savingObject.saveEventually { (success:Bool, error:NSError?) -> Void in
if error == nil
{
// data was saved
}
}
Second Method is to retrieve all the zipcodes from parse. So lets say that we want to query all 2344 zip codes
var needToFoundZipcode = 2344
var queryFromParse = PFQuery(className: "nameoftheclass")
queryFromParse.whereKey("zipcode", equalTo: needToFoundZipcode)
queryFromParse.findObjectsInBackgroundWithBlock { (objects:[AnyObject]?, error:NSError?) -> Void in
if error == nil
{
if let objects = objects as? [PFObject]
{
for SingleZipcode in objects
{
var singlezipcodeFound = SingleZipcode["zipcode"] as! Int
// now you could whatever you want
}
}
}
}

Resources