can't initiate nested block on iOS8 - ios

I am trying to do a nested block inside of another block. It seems that possibly asynchronous requests time out a lot fast on iOS8 as opposed to previous version of iOS. Here is my Parse code:
- (void)getRemoteImageAndSaveLocalWithObjectId:(NSString *)objectId andType:(NSString *)type{
if ([type isEqualToString:#"user"]) {
PFQuery *query = [GAUser query];
//[query includeKey:#"userImage"];
[query getObjectInBackgroundWithId:objectId block:^(PFObject *object, NSError *error) {
GAUser *gaUser = (GAUser *)object;
PFFile *userImageFile = gaUser[#"#userImage"];
[userImageFile getDataInBackgroundWithBlock:^(NSData *data, NSError *error) {
// I am never able to get inside this block of code.
NSLog(#"in get data");
if (!error) {
NSLog(#"remote image name: %#",data.debugDescription);
UIImage *image = [UIImage imageWithData:data];
}else{
NSLog(#"there was an error");
}
}];
}];
}
}
Does anyone know why I can't get in the getDataInBackgroundWithBlock block?

Darren and Andy were right (they're probably brothers).
userImageFile was nil and that was the problem.

Related

Specific part of code not being executed in iOS

I am retrieving data from Parse.com and try to add an image with this data to an array. However, some code is not being executed without any obvious reason. This is the code:
PFQuery *userQuery = [PFUser query];
[userQuery whereKey:#"objectId" containedIn:[self.event objectForKey:#"members"]];
[userQuery findObjectsInBackgroundWithBlock:^(NSArray *users, NSError *error) {
if (!error) {
self.membersArray = [NSMutableArray arrayWithArray:users];
[self.tableView reloadData];
for (PFUser *user in self.membersArray) {
[self.memberPhotosArray addObject:[NSNull null]];
NSInteger index = [self.memberPhotosArray indexOfObject:user];
PFFile *photoFile = [user objectForKey:#"profilePicture"];
[photoFile getDataInBackgroundWithBlock:^(NSData *result, NSError *error) {
if (!error) {
NSLog(#"Before creating image");
UIImage *image = [UIImage imageWithData:result];
[self.memberPhotosArray[index] addObject:image];
NSLog(#"After creating image");
[self.tableView reloadData];
}
}];
}
}
}];
The first log is being executed, everything after this line is not being called. Can someone explain why and provide a solution?
Looks like your code is running on a background thread. Run the code in the final callback block on the main thread.
if (!error) {
NSLog(#"Before creating image");
UIImage *image = [UIImage imageWithData:result];
dispatch_async(dispatch_get_main_queue(), ^{
[self.memberPhotosArray[index] addObject:image];
NSLog(#"After creating image");
[self.tableView reloadData];
});
}
UI related operations should only be performed on the main thread.

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];
}
}];
}];
}

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"];

Retrieving profile picture with parse.com

I set up a profile picture for users following the code here, but I can't seem to retrieve the picture. The code I tried is below please help me out can't seem to figure this out:
PFQuery *query = [PFUser query];
[query getObjectInBackgroundWithId:#"profilePic" block:^(PFObject *object, NSError *error) {
if (!error) {
NSData * imageData = UIImagePNGRepresentation(object);
}
else{
// Error stuff
}
}];
You've misunderstood the purpose of getObjectInBackgroundWithId:block: ... the first parameter is meant to be the ID of the object you want to get. Inside the block you can then query for properties of the object you've gotten.
e.g. if you want the current user:
PFQuery *query = [PFUser query];
[query getObjectInBackgroundWithId:[PFUser currentUser].objectId block:^(PFObject *user, NSError *error) {
if (!error) {
PFFile *profilePic = user[#"profilePic"];
[profilePic getDataInBackgroundWithBlock:^(NSData *imageData, NSError *error) {
if (!error) {
UIImage *image = [UIImage imageWithData:imageData];
}
}];
}
else{
// Error stuff
}
}];

Query PFFile from the pre-defined User class with Parse

I think it's very trivial, but i can't figure it out why these codes are incorrect.
I want to retrieve one image from the Parse User class. I mean, every user has a profile picture, that i store under the "imageFile" column and i would like to load it to a PFImageView. The upload works correctly, but i'cant retrieve it. The log says error, because there is no matches for the query. The file what i want to retrieve exists, so it's 100% that my query implementation is wrong. I would really appreciate any relevant help, thanks.
Non query version: (all versions are implemented in the viewDidLoad)
self.userThumbnail.file = self.currentUser.imageFile;
[self.userThumbnail loadInBackground];
query version
PFQuery *queryImage = [PFQuery queryWithClassName:#"User"];
[queryImage whereKey:#"imageFile" equalTo:self.currentUser]
[queryImage getFirstObjectInBackgroundWithBlock:^(PFObject *object, NSError *error) {
if (error) {
NSLog(#"ERROR");
} else {
PFFile *file = [object objectForKey:#"imageFile"];
self.userThumbnail.file = file;
[self.userThumbnail loadInBackground];
}
}];
query version
PFQuery *queryImage = [PFUser query];
[queryImage whereKey:#"imageFile" equalTo:self.currentUser];
[queryImage getFirstObjectInBackgroundWithBlock:^(PFObject *object, NSError *error) {
if (error) {
NSLog(#"ERROR");
} else {
PFFile *file = [object objectForKey:#"imageFile"];
self.userThumbnail.file = file;
[self.userThumbnail loadInBackground];
}
}];
This line:
[queryImage whereKey:#"imageFile" equalTo:self.currentUser];
looks like a mistake. It says, "find Users whose imageFile column (presumably a PFImage) is equal to the current user object". That will never be true.
Try to separate the logic for finding a user from dealing with it's imageFile. In other words. First get a user:
PFQuery *queryUser = [PFQuery queryWithClassName:#"User"];
[queryUser whereKey:#"username" equalTo:#"some-user-name"];
[queryUser getFirstObjectInBackgroundWithBlock:^(PFObject *user, NSError *error) {}];
// or maybe instead of username==, get a user with their id ...
[queryUser getObjectInBackgroundWithId:#"some-user-id" block:^(PFObject *user, NSError *error) {}];
Now, inside the completion block for querying a user, do your file logic:
[queryUser getFirstObjectInBackgroundWithBlock:^(PFObject *user, NSError *error) {
PFFile *userImageFile = user[#"imageFile"];
[userImageFile getDataInBackgroundWithBlock:^(NSData *imageData, NSError *error) {
if (!error) {
UIImage *image = [UIImage imageWithData:imageData];
// this is a regular UIImage now, put it in your UI
self.someUIImageView.image = image;
}
}];
}];

Resources