How to transfer a variable between two classes - ios

So I have the first class:
- (void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary *)info {
UIImage *chosenImage = info[UIImagePickerControllerOriginalImage];
self.imageView.image = chosenImage;
_camera_button.hidden = true;
_camera_imageview.hidden = false;
[_next_camera setEnabled:YES];
NSData *imageData = UIImagePNGRepresentation(chosenImage);
[self upload_selfie:imageData];
[picker dismissViewControllerAnimated:YES completion:NULL];
}
And I am wanting to transfer the variable: imageData to this class:
- (IBAction)upload_selfie:(NSData *)sender{
PFFile *imageFile = [PFFile fileWithName:#"Image.jpg" data:imageData];
// Save PFFile
[imageFile saveInBackgroundWithBlock:^(BOOL succeeded, NSError *error) {
if (!error) {
// Hide old HUD, show completed HUD (see example for code)
// Create a PFObject around a PFFile and associate it with the current user
PFObject *userPhoto = [PFObject objectWithClassName:#"UserPhoto"];
[userPhoto setObject:imageFile forKey:#"imageFile"];
// Set the access control list to current user for security purposes
userPhoto.ACL = [PFACL ACLWithUser:[PFUser currentUser]];
PFUser *user = [PFUser currentUser];
[userPhoto setObject:user forKey:#"user"];
[userPhoto saveInBackgroundWithBlock:^(BOOL succeeded, NSError *error) {
if (!error) {
// _loader6.hidden = true;
// [self performSegueWithIdentifier:#"toquestion" sender:self];
}
else{
// Log details of the failure
NSLog(#"Error: %# %#", error, [error userInfo]);
}
}];
}
}];
}
Where I have tried:
PFFile *imageFile = [PFFile fileWithName:#"Image.jpg" data:imageData];
But I receive the error "Use of undeclared identifier"?ces where I refrence imageData should I somewhere else?
Also these are the only two pla
Please may you explain why and what I can do about this?

You receive this error because your variable name is sender:
- (IBAction)upload_selfie:(NSData *)sender
You need change your code to:
PFFile *imageFile = [PFFile fileWithName:#"Image.jpg" data:sender];
PS. It seems that you use upload_selfie: method for two aims: a) interface builder action handler; b) method for saving photo. It is better to make two separate methods.

You're passing the parameter as sender so that's the name you should use: PFFile *imageFile = [PFFile fileWithName:#"Image.jpg" data:sender];.
Though, to be more understandable, choosing a different name would be good.

Related

App freezes until image is downloaded and shown. Parse

I am using Parse.com
When I download my PFFile(contains image) in viewDidAppear my app freezes for a while and then it shows the pic. But that is not right. I want UIActivityIndicatorView to be animated or at least shown. I know that this deals with async or something. But I have no idea how to make that work correctly.
PFFile* imageFile = [[PFUser currentUser] objectForKey:#"profilePic"];
if (imageFile) {
self.activity.hidden = NO;
[self.activity startAnimating];
NSURL* imageFileUrl = [[NSURL alloc]initWithString:imageFile.url];
NSData* imageData = [NSData dataWithContentsOfURL:imageFileUrl];
self.profilePic.image = [UIImage imageWithData:imageData];
}
This downloads the image and shows it.
UPD:
PFQuery* query = [PFUser query];
[query valueForKey:#"profilePic"];
[query findObjectsInBackgroundWithBlock:^(NSArray* data, NSError* error)
{
PFFile* imageFile = data[0];
[imageFile getDataInBackgroundWithBlock:^(NSData* data,NSError* error){
if (!error) {
self.activity.hidden = NO;
[self.activity startAnimating];
NSURL* imageFileUrl = [[NSURL alloc]initWithString:imageFile.url];
NSData* imageData = [NSData dataWithContentsOfURL:imageFileUrl];
self.profilePic.image = [UIImage imageWithData:imageData];
}else{
self.profilePic.image = [UIImage imageNamed:#"profile#2.png"];
}
}];
}];
UPD 2:
This solved my problem. Both answers were helpful.
PFQuery* query = [PFUser query];
[query getObjectInBackgroundWithId:[PFUser currentUser].objectId block:^(PFObject* object, NSError* error){
if(!error){
PFFile* imageFile = object[#"profilePic"];
[imageFile getDataInBackgroundWithBlock:^(NSData* data, NSError* error) {
if (!error) {
self.activity.hidden = NO;
[self.activity startAnimating];
self.profilePic.image = [UIImage imageWithData:data];
NSLog(#"Profile pic shown");
}
else{
NSLog(#"Error 2: %#",error);
}
}];
}else{
self.profilePic.image = [UIImage imageNamed:#"profile#2.png"];
NSLog(#"Fail 1 : %#",error);
}
}];
This is because you are not getting the object in the background. Try using a query to accomplish this. If you need more info I can give you the full query as I have this code inside my app :)
Sample code:
[query findObjectsInBackgroundWithBlock:^(NSArray *objects, NSError *error) {}];
To get an image with data:
PFFile *imageFile = [object objectForKey:#"YOURKEY"];
[imageFile getDataInBackgroundWithBlock:^(NSData *data, NSError *error) {}];
There are couple of things wrong with your code
Your query is not right, I can't understand this part [query valueForKey:#"profilePic"]; if you want to get user have profile pics then you should do something like this [query whereKeyExist:#"profilePic"];, but at the moment query you have will bring down all objects.
You are downloading image in main thread which make your app free you should do something like this
[imageFile getDataInBackgroundWithBlock:^(NSData *imageData, NSError *error) {
if (!error)
{
self.profilePic.image = [UIImage imageWithData:imageData];
}
}];
You must check data.count before calling data[0], this could crash your application if data array is nil or empty.
Update:
Getting profile pic for currentUser will be something like this
PFUser *currentUser = [PFuser currentUser];
if (!currentUser)
{
//need to login
}
else
{
// may be you need to fetch
__weak typeof(self) weakSelf = self;
[currentUser fetchIfNeededInBackgroundWithBlock:^(PFObject *obj, NSError *error){
PFFile* imageFile = [[PFUser currentUser] objectForKey:#"profilePic"];
[imageFile getDataInBackgroundWithBlock:^(NSData *imageData, NSError *error) {
if (!error)
{
weakSelf.profilePic.image = [UIImage imageWithData:imageData];
}
}];
}];
}

Best way to cache images from Parse with cellForRowAtIndexPath

I was normally trying to load the image for each cell like so in my UITableView using Parse SDK:
PFRelation *relation = [object relationForKey:#"images"];
PFQuery *relationQuery = [relation query];
[relationQuery getFirstObjectInBackgroundWithBlock:^(PFObject *obj, NSError *error) {
if (!error)
{
// Adding Image to ImageView
if ([obj objectForKey:#"image"])
{
PFFile *image = (PFFile *)[obj objectForKey:#"image"];
[image getDataInBackgroundWithBlock:^(NSData *data, NSError *error){
if (error)
{
cell.carPhoto.image = [UIImage imageNamed:#"placeholder.png"];
}
else
{
UIImage *carImage = [UIImage imageWithData:data];
cell.carPhoto.image = carImage;
}
}];
}
else
{
cell.carPhoto.image = [UIImage imageNamed:#"placeholder.png"];
}
}
}];
The issues with that, is that it is using way too many queries and the cells have a little lag when scrolling and show the pic above for a brief second before the actual. I attempted to change my code to this to use SDWebImage:
PFRelation *relation = [object relationForKey:#"images"];
PFQuery *relationQuery = [relation query];
[relationQuery getFirstObjectInBackgroundWithBlock:^(PFObject *obj, NSError *error) {
if (!error)
{
// Adding Image to ImageView
if ([obj objectForKey:#"image"])
{
PFFile *image = (PFFile *)[obj objectForKey:#"image"];
NSString *theUrl = image.url;
NSLog(#"%#", theUrl);
[cell.carPhoto setImageWithURL:[NSURL URLWithString:[theUrl stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding]]
placeholderImage:nil];
}
else
{
cell.carPhoto.image = [UIImage imageNamed:#"placeholder.png"];
}
}
}];
But now I keep getting: -[UIImageView setImageWithURL:placeholderImage:]: unrecognized selector sent to instance 0x7c04ab40. Basically my end goal is to have it so images aren't queried every time the tableView is scrolled, and are cached. Any ideas?

How to get pffile from pfobject using Parse

I am trying to get a file from my PFUser object with by simply:
PFFile *userImageFile = gaUser[#"#userImage"];
This returns nil.
This is what it looks like in my method:
- (void)getRemoteImageAndSaveLocalWithObjectId:(NSString *)objectId andType:(NSString *)type{
if ([type isEqualToString:#"user"]) {
PFQuery *query = [GAUser query];
// I tried the include key but I get an error.
//[query includeKey:#"userImage"];
[query getObjectInBackgroundWithId:objectId block:^(PFObject *object, NSError *error) {
GAUser *gaUser = (GAUser *)object;
// this is nil
PFFile *userImageFile = gaUser[#"userImage"];
if (userImageFile){
[userImageFile getDataInBackgroundWithBlock:^(NSData *data, NSError *error) {
NSLog(#"in get data");
if (!error) {
NSLog(#"remote image name: %#",data.debugDescription);
UIImage *image = [UIImage imageWithData:data];
}else{
NSLog(#"there was an error");
}
}];
}else{
NSLog(#"user image file is nil");
}
}];
}
This prints: user image file is nil
My parse console looks like:
What am I doing wrong?
Since in Parse your column is named userImage, you should be accessing it with:
PFFile *userImageFile = gaUser[#"userImage"];
instead of
PFFile *userImageFile = gaUser[#"#userImage"];

Passing Data to Singleton iOS

I'm currently having some trouble with data getting lost when transferring from a ViewController to a subclass of PFFile. The data being passed is image data to upload to a users profile. Here's the code for selecting the image:
- (void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary *)info
{
// Access the uncropped image from info dictionary
UIImage *image = [info objectForKey:#"UIImagePickerControllerOriginalImage"];
// Dismiss controller
[picker dismissViewControllerAnimated:YES completion:nil];
// Resize image
_focusedImage.image = image;
NSData *imageData = UIImageJPEGRepresentation(image, 0.05f);
PFFile *imageFile = [PFFile fileWithName:#"Image.jpg" data:imageData];
[[imageUpload uploadImage] setImagePFFile:imageFile];
}
The Log on imageFile in this view is printing out correctly. However, when I pass the data through to my singleton class imageUpload uploadImage This is what the data structure looks like:
+ (imageUpload *) uploadImage
{
static imageUpload*_sharedImageUpload = nil;
_sharedImageUpload = [[self alloc] init];
_sharedImageUpload.imageData = [[NSData alloc] init];
PFUser *user = [PFUser currentUser];
_sharedImageUpload.imagePFFile = [[PFFile alloc] init];
PFFile *imageFile = [PFFile fileWithName:#"Image.jpg" data:_sharedImageUpload.imageData];
[imageFile saveInBackgroundWithBlock:^(BOOL succeeded, NSError *error) {
if (!error)
{
[user setObject:imageFile forKey:#"image"];
[user saveInBackgroundWithBlock:^(BOOL succeeded, NSError *error) {
if (!error)
{
NSLog(#"This should be the profile image upload");
}
else
{
NSLog(#"Something went wrong: %#", error);
}
}];
}
}];
return _sharedImageUpload;
}
When I get to this point, the system just uploads a blank file (zero bytes) to Parse. The naming is right and its going in the right place on the database, but somewhere along the line the data in the file itself is being lost. I can't figure out why. Does anyone have any suggestions?
It looks like you're confusing objects and methods. What you want is a singleton object that has a method / function that uploads your image. I think this is what you're looking for:
//ImageUploader.h
#import <Foundation/Foundation.h>
#interface ImageUploader : NSObject
+ (instancetype)uploader;
- (void)uploadImageFile:(PFFile *)aFile;
#end
//ImageUploader.m
#import "ImageUploader.h"
#implementation ImageUploader
+ (instancetype)uploader {
static ImageUploader * _uploader = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
_uploader = [[self alloc] init];
});
return _uploader;
}
-(void)uploadPFFile:(PFFile *)imageFile{
[imageFile saveInBackgroundWithBlock:^(BOOL succeeded, NSError *error) {
if (!error)
{
[user setObject:imageFile forKey:#"image"];
[user saveInBackgroundWithBlock:^(BOOL succeeded, NSError *error) {
if (!error)
{
NSLog(#"This should be the profile image upload");
}
else
{
NSLog(#"Something went wrong: %#", error);
}
}];
}
}];
}
#end
You invoke it by calling [[ImageUploader uploader]uploadImageFile:someFile].

Saving an Image using Parse SDK

Taking Image:
I'm taking the image using the code in this question:
Scaling UIImage with a UIIImagePicker's CGAffineTransform and Saving to Parse SDK
Convert UIImage to NSData & Save
_imageData = UIImageJPEGRepresentation(_image, .1);
PFFile *imageFile = [PFFile fileWithName:#"image.png" data:_imageData];
newMessage[#"image"] = imageFile;
Problem:
When I redownload the data, the UIImage appears squished. When I look at the image on my database, it seems like the height and width are reversed. Not sure why this is happening...
NSData *imageData = UIImageJPEGRepresentation(yourImage, 1.0);
PFFile *imageFile = [PFFile fileWithName:#"Image.jpg" data:imageData];
PFObject *userPhoto = [PFObject objectWithClassName:#"Photo"];
[userPhoto setObject:imageFile forKey:#"image"];
// Set the access control list to current user for security purposes
userPhoto.ACL = [PFACL ACLWithUser:[PFUser currentUser]];
[userPhoto setObject:user forKey:#"user"];
[userPhoto saveInBackgroundWithBlock:^(BOOL succeeded, NSError *error) {
if (!error) {
NSLog(#"sucess");
}
else{
// Log details of the failure
NSLog(#"Error: %# %#", error, [error userInfo]);
}
[[ConnectionManager sharedManager] removeload];
}];

Resources