简体   繁体   中英

How to create an array of UIImages

I'm storing an image from a Parse database like this:

PFFile *firstImageFile = self.product[@"firstThumbnailFile"];
[firstImageFile getDataInBackgroundWithBlock:^(NSData *imageData, NSError *error) {
    if (!error) {
        self.firstImage = [UIImage imageWithData:imageData];
    }
}];

I want to save the images as an array to display them inside a scrollview.

It works if I do something like this:

self.galleryImages = [NSArray arrayWithObjects: [UIImage imageNamed:@"s2.jpg"], [UIImage imageNamed:@"s1.jpg"], nil];

But if I try to use the UIImage itself, no image appears.

self.galleryImages = [NSArray arrayWithObjects: self.firstImage, self.secondImage, nil];

Any help? Thanks.

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.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM