I\'m storing an image from a Parse database like this:
PFFile *firstImageFile = self.product[@\"firstThumbnailFile\"];
[firstImageFile getDataInBackgroundWithBlo
This is form of a common problem: how to do many asynch operations (without deeply nesting completion blocks) and know when they complete. The approach I use is to think of the parameters to the operations as a todo list, and build a method that handles the list recursively....
- (void)loadPFFiles:(NSArray *)array filling:(NSMutableDictonary *)results completion:(void (^)(BOOL))completion {
NSInteger count = array.count;
// degenerate case is an empty array which means we're done
if (!count) return completion(YES);
// otherwise, do the first operation on the to do list, then do the remainder
PFFile *file = array[0];
NSArray *remainder = [array subarrayWithRange:NSMakeRange(0, count-1)];
[file getDataInBackgroundWithBlock:^(NSData *imageData, NSError *error) {
if (!error) {
UIImage *image = [UIImage imageWithData:imageData];
results[file.name] = image;
[self loadPFFiles:remainder filling:results completion:completion];
} else {
completion(NO);
}
}];
}
Call it like this (guessing about your model a little bit):
NSArray *pfFiles = @[ self.product[@"firstThumbnailFile"], self.product[@"secondThumbnailFile"] ];
NSMutableDictionary *result = [@{} mutableCopy];
[self loadPFFiles:pfFiles filling:result completion:^(BOOL success) {
if (success) {
// result will be an dictionary of the loaded images
// indexed by the file names
}
}];
I would guess (based on your comments about nil above) that your code looks a little like this:
PFFile *firstImageFile = self.product[@"firstThumbnailFile"];
[firstImageFile getDataInBackgroundWithBlock:^(NSData *imageData, NSError *error) {
if (!error) {
self.firstImage = [UIImage imageWithData:imageData];
}
}];
self.galleryImages = [NSArray arrayWithObjects: self.firstImage, self.secondImage, nil];
If this is the case, move the array initialization inside the completion block like so:
PFFile *firstImageFile = self.product[@"firstThumbnailFile"];
[firstImageFile getDataInBackgroundWithBlock:^(NSData *imageData, NSError *error) {
if (!error) {
self.firstImage = [UIImage imageWithData:imageData];
dispatch_async(dispatch_get_main_queue(), ^{
self.galleryImages = [NSArray arrayWithObjects: self.firstImage, self.secondImage, nil];
});
}
}];
What happens in the first (your) case is that the array initialization statement runs before the completion block, so when 'first image' is actually set it is too late as the array has already been initialized.