This works as expected:
// Return a sequence for photos
[[[[[[RACObserve(self, event.photos) filter:^BOOL(id value) { return value != 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
map:^id(NSDictionary *selectedPhotoDescriptor)
{
NSLog(@"Photo URL: %@" , selectedPhotoDescriptor[@"url"]) ;
return [[AsyncImageFetcher imageAtURL:[NSURL URLWithString:selectedPhotoDescriptor[@"url"]] cache:YES] firstOrDefault:[UIImage imageNamed:@"detail_placeholder"]] ;
}]
// Deliver on main thread
deliverOn:RACScheduler.mainThreadScheduler]
subscribeNext:^(id x)
{
((UIImageView *)self.headerView).image = x ;
}] ;
This does not; the image is never set:
RAC( ((UIImageView *)self.headerView), image ) =
// Return a sequence for photos
[[[[[RACObserve(self, event.photos) filter:^BOOL(id value) { return value != 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
map:^id(NSDictionary *selectedPhotoDescriptor)
{
NSLog(@"Photo URL: %@" , selectedPhotoDescriptor[@"url"]) ;
return [[AsyncImageFetcher imageAtURL:[NSURL URLWithString:selectedPhotoDescriptor[@"url"]] cache:YES] firstOrDefault:[UIImage imageNamed:@"detail_placeholder"]] ;
}]
// Deliver on main thread
deliverOn:RACScheduler.mainThreadScheduler] ;
Why?
Here is the version that works:
// 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
[[[[RACObserve(self, event.photos) 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
}] ;
Note that AsyncImageFetcher
's imageAtURL:cache:
returns a signal.
A few notes about this solution:
First I had to create a new private property self.imageView
that does nothing but return self.headerView
. The reason for this relates to the arguments that the RAC()
macro can accept. I became suspicious that the parameters I was passing to RAC()
was causing my problem, so I simplified it by doing the cast in the aforementioned private property:
@synthesize imageView ;
- (UIImageView *) imageView
{
return (id) self.headerView ;
}
Then I tried:
RAC( self.imageView, image ) = …
But this didn't work. I then tried
RAC( self, imageView.image ) = …
This worked! So then I thought, let's get rid of self.imageView
and see if it works with the casting right in the macro:
RAC( self, (((UIImageView *)headerView).image) ) = …
Unfortunately, this yields a syntax error.
So, the solution that utilizes the casting private property works, but it feels like a workaround. I'm accepting the answer since it works for me, but I'd still like to know if there's a way I can do this without creating the (redundant) imageView property.