I understand that this function first return "images" then "findObjectsInBackgroundWithBlock" retrieve data that's why results is nil.
1 - how to return array from block?
2 - how to put this block not in main thread?
+(NSMutableArray *)fetchAllImages{
__block NSMutableArray *images = [NSMutableArray array];
PFQuery *query = [PFQuery queryWithClassName:@"Photo"];
[query findObjectsInBackgroundWithBlock:^(NSArray *objects, NSError *error) {
if (!error) {
for (PFObject *object in objects) {
PFFile *applicantResume = object[@"imageFile"];
NSData *imageData = [applicantResume getData];
NSString *imageName = [ImageFetcher saveImageLocalyWithData:imageData FileName:object.objectId AndExtention:@"png"];
[images addObject:imageName];
// here images is not empty
}
} else {
NSLog(@"Error: %@ %@", error, [error userInfo]);
}
}];
// here images is empty
return images;
}
The method performs its work asynchronously, and the caller needs to know that. So,
Do not:
+(NSMutableArray *)fetchAllImages{
return an array, because the array is not ready at the time of return.
Do:
+ (void)fetchAllImages {
return nothing, because that's what you have when the method finishes execution.
But how to give the images to the caller? The same way that findObjectsInBackgroundWithBlock
does, with a block of code that runs later....
Do:
+ (void)fetchAllImagesWithBlock:(void (^)(NSArray *, NSError *)block {
Then, using your code from within the findBlock:
[images addObject:imageName];
// here images is not empty
// good, so give the images to our caller
block(images, nil);
// and from your code, if there's an error, let the caller know that too
NSLog(@"Error: %@ %@", error, [error userInfo]);
block(nil, error);
Now your internal caller calls this method just like your fetch code calls parse:
[MyClassThatFetches fetchAllImagesWithBlock:^(NSArray *images, NSError *error) {
// you can update your UI here
}];
Regarding your question about the main thread: you want the network request to run off the main, and it does. You want the code that runs after it finishes to run ON the main, so you can safely update the UI.
It doesn't work that way.
You are calling an asynchronous method. You can't wait for the result of an asynchronous method and return the result (well, you can, but not if you are asking how to do it on stackoverflow). With an asynchronous block, you trigger an action, and it is up to the completion block to deliver the results where they are needed.
There are gazillions of examples how to do this on stackoverflow. Looking for them is your job.