Display random image with ImageView - ios

I finally was able to pull an array of images from Parse.com after fiddling with tutorials.
From that array I want to throw it on an image view via next random image with a swipe gesture:
var query = PFQuery(className:"cats")
query.findObjectsInBackgroundWithBlock {(objects: [AnyObject]?, error: NSError?) -> Void in
if error == nil {
// The find succeeded.
for object in objects! {
// Update - replaced as with as!
self.imageFiles.append(object as! PFObject)
println(self.imageFiles)
self.view.addGestureRecognizer(rightSwipe)
}
} else {
// Log details of the failure
println(error)
}
}
}
The println(self.imageFiles) actually shows the array of files which is great, what I'm having issues with is using the random generator.
Still new to syntax, I was trying to do like imageview.image = imageFiles[0] or something like that to just display one of the images in the array. Not really sure the syntax though.
I'm guessing once I get that it would be imageview.image = imageFiles[RandomNumber] or the equivalent.
for the swipe part I think I got that under control
Edit
ok I have:
let randomNumber = imageFiles[Int(arc4random_uniform(UInt32(imageFiles.count)))]
println(randomNumber)
and the println gives me a random image file from the array.
How do I put that into the image view?
EDIT
just tried:
for randomNumber in imageFiles {
self.ImageView.image = randomNumber
}
and got:
cannot assign a value type pfobject to a value type of uiimage
self.ImageView.image = UIImage(data: randomNumber)
also gives me an error can't have data: PFObject

Related

Parse array images saving and fetching

I have a mosaic app that takes multiple size photos and breaks them into smaller photos. Depending on the size of the photo, the amount of smaller photos could vary. Now I have an NSMutableArray named imageNameList2 that holds all of the smaller images taken from the larger image. For this example I showed an example with the images being called from the image assets list to make it easier to answer this question.
Here is the imageNameList (NSMutableArray that holds all the smaller images)
var imageNameList: [String] {
var imageNameList2:[String] = [] //[NSMutableArray]()
for i in 0...149 {
let imageName = String(format: "pic_%03d", Int(i))
imageNameList2.append(imageName)
}
return imageNameList2
}
What I'd like to do is have a continue button that will save all these images in order as piffles or any other format to parse that works best and have another button called retrieve that will retrieve all these photos from parse. I basically have a parse server that utilizes parse frameworks to help speed up the backend process. Can you please show me how I would save and retrieve this NSMutableArray if there are different numbers of stored images each time?
I think you're trying to do something like this. This is just an example. There's a lot of work to be done but hopefully this will get you started. I did not run or test this code.
The idea is to save your images as PFFiles, and create a 'tile' PFObject for each file. Then save all the 'tile' PFObjects to a 'tiles' key of the image PFObject. Then recall the image when you need it by objectId.
Good luck.
let appleTiles = ["apple1, apple2, apple3"]
let orangeTiles = ["orange1, orange2, orange3, orange4, orange5"]
func usage() {
//dont literally run these synchronously like this
post(appleTiles)
post(orangeTiles)
download()
}
func post(_ tileNames: [String]) {
let image = PFObject(className: "Image")
let tilesPF = tileNames.map({ name in
let data = UIImagePNGRepresentation(UIImage(named: name))!
let file = PFFile(data: data)
let tile = PFObject(className: "Tile")
tile["tile"] = file
})
image["tiles"] = tilesPF
image?.saveInBackground(block: { responseObject, error in
//you'll want to save the object ID of the PFObject if you want to retrieve a specific image later
})
}
func download() {
let query = PFQuery(className: "image")
//add this if you have a specific image you want to get
query.whereKey("objectId", equalTo: "someObjectId")
query.findObjectsInBackground({ result, error in
//this is probably close to how you'd unwrap everything but again, I didn't test it so...
if let objects = result as? [PFObject], let first = objects.first, let image = first["image"] as? PFObject, let tiles = image["tiles"] as? [PFObject] {
tiles.forEach({ tile in
let file = tile["tile"]
//now you have an individual PFFile for a tile, do something with it
})
}
})
}

Adding image from Firebase to UITableViewCell

I want to retrieve the image that is stored in the storage of an user and place it next to his name in a custom UITableViewCell. The problem now is that the tableview will load when the images aren't done downloading (I think?), causing the application to crash because the image array is nil. So what is the correct way to load the tableview? I think, for the user experience, it is important that the tableviewcell image should be shown even if the images aren't done downloading, and present them a default image that is saved in the assists. I thought about making an array with UIImages that links to the default asset of loading an image and changing the image to the profile picture when it is done downloading. But I really have no clue how to do that. This is what I got so far about downloading the image:
let storage = FIRStorage.storage()
let storageRef = storage.reference(forURL: "link.appspot.com")
channelRef?.observeSingleEvent(of: .value, with: { (snapshot) in
if let snapDict = snapshot.value as? [String:AnyObject]{
for each in snapDict{
let UIDs = each.value["userID"] as? String
if let allUIDS = UIDs{
let profilePicRef = storageRef.child((allUIDS)+"/profile_picture.png")
profilePicRef.data(withMaxSize: 1 * 500 * 500) { data, error in
if let error = error {
}
if (data != nil)
{
self.playerImages.append(UIImage (data: data!)!)
}
}
}
let userNames = each.value["username"] as? String
if let users = userNames{
self.players.append(users)
}
}
}
self.tableView.reloadData()
})
This is in the cellForRow
cell.playersImage.image = playerImages[indexPath.row] as UIImage
My rules, haven't changed it from the default rules:
service firebase.storage {
match /b/omega-towers-f5beb.appspot.com/o {
match /{allPaths=**} {
allow read, write: if request.auth != null;
}
}
}
Thank you.
Regarding user experience, you are correct. It is standard to have some sort of default image when loading an image from a URL. A great library to use for image caching and using default assets in its' place is AlamofireImage
Vandan Patel's answer is correct in saying you need to ensure your array is not nil when loading the tableview. You will be given a completion block to handle any extra work you would like to do with your image, using the AlamofireImage library.
This is all assuming you are getting a correct image URL back for your Firebase users.
You should call tableView.reloadData() when the images are done downloading. One important thing, initialize your playerImages as playerImages = [UIImage]() instead of playerImages: [UIImage]!. if it's empty, it wouldn't show your array is nil.
Update:
if let players = playerImages {
//code
}

Querying from Parse

Basically I am trying to display 3 users, I am querying from the _User class the following: username, profilePicture & Name.
After that I would like to query the last photo they posted from the Posts class.
Here is how I have setup my code :
let userQuery = PFQuery(className: "_User")
userQuery.limit = 3
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 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 object in objects! {
self.lastPicArray.append(object.valueForKey("image") as! PFFile)
}
self.collectionView.reloadData()
} else {
print(error!.localizedDescription)
}
})
} else {
print(error!.localizedDescription)
}
})
}
But when I run it, it isn't showing the correct image for the user showing...I cannot get my head round it, it's been driving me mad for several hours now!!
The background thread isn't a problem for fetching your images, but your image query is not set to return images in any specific order, nor does it seem to limit how many photos will come back for each user (unless you have it set up so that the Post object can only hold one post per user). You could handle this in a few different ways, but the easiest way might be to sort your object array in some predictable order, using the username as the sort key, and then when you get your images back you can sort them in the same order based on their username property before putting them into the array that drives the collectionView.
One other note - you'll want to put your .reloadData() call back on the main thread or it'll happen at an unpredictable time.
It might cause by data transferring in different time cost since you use findObjectsInBackgroundWithBlock. Threads running in background are hard to control. So the order of images in imageQuery objects is different with usernameArray. Or findObjectsInBackgroundWithBlock doesn't guarantee that data will be fetched in same order with keys set. Not 100% sure about this.
But try putting the image fetching procedure inside the first for object in objects! loop. It might be able to solve your problem.
For sorting answer from creeperspeak, you should be able to get username back from imageQuery class just like object.valueForKey("username") in your first loop. Then match them with self.usernameArray.

PFFile to UIImage in Parse (ios)

I am trying to convert a PFFile to a UIImage. It works, however, it doesn't seem to run until the very end. The line after the image is called appends the image to the array (photosArray.append(image!)), but when I do this, it doesnt work, and stores nothing. I believe this is because since the image hasnt been fully retrieved yet because it is grabbing the image in the background. How do I not have it save in the background, but wait until all the data is loaded, THEN append to the photosArray image, so the array isnt empty?
var photosArray = [UIImage]()
let photosValue = log["Images"] as! PFFile
photosValue.getDataInBackgroundWithBlock({
(imageData: NSData?, error:NSError?) -> Void in
if (error == nil) {
let image = UIImage(data:imageData!)
//line below appends nothing! photosArray is an empty array, []
photosArray.append(image!)
//following line of code doesnt run until the end. Is the last line to be printed in console.
println("Our Image: \(image)")
}
})
//prints "[]", no value
println(photosArray)
println("Our Image Array^^")
}
//after all the code is ran, the println("Our Image: \(image)") will run,
//and say "Our Image: Optional(<UIImage: 0x16f0ead0>, {394, 256})".
//This is the last line of the console logged, so it IS saving, but not until the end.
That is not a correct assumption, the whole point of the getDataInBackgroundWithBlock is to handle the response data. You also wouldn't be able to assign
let image = UIImage(data: imageData!)
if it were nil.
I'm not sure about what println statements you're referring to, however printing out the array while data is still being collected in the background may not give you a result, and just
[]
But you should see
println("Our image: \(image)")
If you plan to display these images inside a UIImageView I suggest taking a look at the ParseUI class PFImageView, which has a property you can assign a PFFile to and then a method in which to load it.

How do i change this code to query by creation date with swift from parse data?

I have this code to retrieve images from parse data.
How do I query it by creation date? I tried using findObjectsInBackgroundWithBlock but it wont work with a PFFile. What do i do?
Also, as a side question, sometimes when i place the images in a UIImageView they are upside down or sideways. Why?
if let objects = objects as? [PFObject] {
for object in objects {
if let userPicture = object.valueForKey("Image") as? PFFile {
userPicture.getDataInBackgroundWithBlock({ (imageData: NSData?, error: NSError?) -> Void in
if (error == nil)
{
let image = UIImage(data:imageData!)
self.ImageArray.insert(image!, atIndex: 0)
}
else {
self.alert("Error: \(error!) \(error!.userInfo!)", Message: "Make sure you have a secure internet connection")
}
dispatch_async(dispatch_get_main_queue())
{
self.collectionView.reloadData()
println("Finished Pictures")
}
})
}
}}
You have a set of objects which all reference an image file, but probably a set of other things too, and the image can likely be changed. So, the object creation date isn't the same as the image creation date and the image file doesn't know (or at least doesn't expose) it's creation date. You're also currently always adding the images to the start of the array so the position will be set by how big (and therefore how long it takes to download) each image is. Also, trying to download lots of images at the same time could just mean you get lots of timeouts.
So, really you should have a column on your object which holds the date at which the image was updated, and sort the objects by that date. As you download the images you place them into the image array in the same index as the owning object in its array (pad the array out with NSNull so you know what's going on).

Resources