0

I have the following code that runs through a series of image records, tries to find a record that's marked "primary", loads it, and assigns it to a UIImageView:

    // When there's a new image, fetch it, and set the headerView (which by default is an UIImageView)
RAC( self, imageView.image ) =

    // Return a sequence for photos
    [[[[[[self modelImagesSignal] ignore:nil] flattenMap:^RACStream *(NSDictionary *photos)
        {
        NSLog(@"Got photos: %@" , photos) ;
        return photos.rac_sequence.signal ;
        }]

    // Consider each photo
    filter:^BOOL(NSDictionary *photoDescriptor)
        {
        NSLog(@"Descriptor: %@" , photoDescriptor) ;
        return ((NSNumber *)photoDescriptor[@"primary"]).boolValue ;
        }]

    // Load the selected photo
    flattenMap:^RACStream *(NSDictionary *selectedPhotoDescriptor)
        {
        NSLog(@"selected photo desc: %@" , selectedPhotoDescriptor) ;
        return [AsyncImageFetcher imageAtURL:[NSURL URLWithString:selectedPhotoDescriptor[@"url"]] cache:YES] ; // This will -deliverOn: the main thread
        }]

    // Catch errors
    catch:^RACSignal *(NSError *error)
        {
        FLASH_REPORT_T(error.description, nil, xkFlashMessageTypeError) ;
        return [RACSignal empty] ;
        }] ;
  1. If there is no primary, I'd like to return the first record encountered, whether it's primary or not, and
  2. If there aren't any records encountered at all, I'd like to return a default image.

How can I do these?

leftspin
  • 2,468
  • 1
  • 25
  • 40

1 Answers1

3
  1. If there is no primary, I'd like to return the first record encountered, whether it's primary or not, and
  2. If there aren't any records encountered at all, I'd like to return a default image.

This isn't using your original code, but extracting out the basics of what you are asking for, here is one way to compose signals to get what you want:

MyImageModel *myDefaultImageModel = [self createDefaultImageModel];

RACSignal *images = [self fetchImagesOrWhatever];
RACSignal *primaryImages = [images filter:^(MyImageModel *im) { return im.isPrimary; }];
RACSignal *defaultImage = [RACSignal return:myDefaultImageModel];

// This is the line to pay attention to:
RACSignal *finalImage = [[[primaryImages concat:[images concat:defaultImage]]] take:1];

RAC(self, imageView.image) = [finalImage map:^(MyImageModel *im) {
    // Convert MyImageModel to a UIImage here, and return it.
}];

This code constructs one signal, called finalImage, that consists of the following values, in order:

  1. Every image that is marked "primary".
  2. The first image (from the same signal of images that fed #1).
  3. A default image.

and then uses -[RACSignal take:1] to take the first of these. If #1 or #2 could be empty signals (because there are no primaries or no images at all), you know that you will at least get #3.

erikprice
  • 6,240
  • 3
  • 30
  • 40
  • Thank you, that basically worked. I did notice though that it only worked if I concat'ed my `images` to the `defaultImage`. It didn't work concat'ing the `defaultImage` to `images`. Not exactly sure why. – leftspin Mar 25 '14 at 19:30
  • According to your original requirements, the order of concatenation should be `primaryImages ++ images ++ defaultImage`. Then when you `-take:1` on the resulting signal, you will get the first primary image, failing that you will get the first image, and failing that you will get the default image. This concatenation is *associative* (in the mathematic sense). If you're concatenating them in some other order, I wonder if there is some other problem with your code. – erikprice Mar 26 '14 at 13:02
  • Thank you for the answer. I have problem with this approach. When I use take:1, even if #1 returns value, #2 gets subscribed anyways (value is ignored though). So if #2, for example, performs a network operation, it will start it, even if #1 returns a value. Do you know, how to prevent that? I mean prevent #2 to execute its work, if #1 returns? Small proof: https://db.tt/sTVLwHuo – Andrew Slabko Feb 11 '15 at 18:12
  • That sounds like a bug in ReactiveCocoa. – erikprice Feb 12 '15 at 21:38