سؤال

I have the following code in my VC:

[RACObserve(self.viewModel, searchMode) subscribeNext:^(NSNumber *value) {
    @strongify(self);
    BOOL isSearchMode = [value boolValue];
    self.searchBarView.hidden = !isSearchMode;
    if (isSearchMode) {
        [self.searchBar becomeFirstResponder];
        self.yContentOffset = self.collectionView.contentOffset.y;
        [self.collectionView setContentOffset:CGPointMake(self.collectionView.contentOffset.x, 0) animated:NO];
    } else {
        [self.searchBar resignFirstResponder];
        [self.collectionView setContentOffset:CGPointMake(self.collectionView.contentOffset.x, self.yContentOffset) animated:NO];
    }
}];

where yContentOffset is VC's property which I am trying to remove. (It saves content offset before entering search mode and restores it after).

I've tried [RACSignal if: then: else:] but did not managed to get it completely.

هل كانت مفيدة؟

المحلول

You've got three distinct values that need to change when self.viewModel.searchMode does, so I think the first thing you want to do is split the signal and take each of them separately.

RACSignal * searchModeSig = [[RACObserve(self.viewModel, searchMode) distinctUntilChanged] 
                                 publish] 
                             signal];

The hidden status is simple:

RAC(self.searchBarView, hidden) = [searchModeSig not];

I used distinctUntilChanged above because your signal to the collection view's y offset seems to be "0 if the searchMode is YES, else the last non-zero value". If the searchMode signal's value were to be YES or NO in succession, you'd also end up with a duplication in the stream of offset values, which would screw up using replayLast to get the value you want. distinctUntilChanged only passes along values that represent a transition from YES to NO or vice-versa.

RAC(self.collectionView, contentOffset) = 
    [RACSignal if:searchModeSig
             then:[RACSignal return:[NSValue valueWithCGPoint:CGPointMake(self.collectionView.contentOffset.x, 0)]
             else:[RACObserve(self.collectionView, contentOffset) replayLast]];

This should insert the 0 y value into the stream whenever searchMode transitions to YES, and take the previous value (which, of course, could have been updated from elsewhere) whenever it transitions to NO.

For the first responder status of the search bar, it seems reasonable to do that with subscribeNext:, but you could also do this:

RAC(self.searchBar, DLShouldBeFirstResponder) = searchModeSig;

Where you've turned the becomeFirstResponder and resignFirstResponder calls into a pseudo-property like so:

@interface UIView (DLFirstResponderProp)

@property (assign, nonatomic) BOOL DLShouldBeFirstResponder;

@end


@implementation UIView (DLFirstResponderProp)

- (void)setDLShouldBeFirstResponder:(BOOL)shouldBe
{
    if( shouldBe ){
        [self becomeFirstResponder];
    }
    else {
        [self resignFirstResponder];
    }
}

- (BOOL)DLShouldBeFirstResponder
{
    return [self isFirstResponder];
}

@end

It might also be that lifting would be the "official" way to go from signal to imperative call, but I'm not sure how/if that works with parameterless methods.

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top