Created
January 23, 2015 16:02
-
-
Save manmal/201a905b290f3e1e09f0 to your computer and use it in GitHub Desktop.
Reactive Search Table View Model
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
@interface MMBaseReactiveSearchTableViewModel() | |
// Most of these will actually be public/header file | |
@property (copy, nonatomic) NSArray *searchResults; | |
@property (copy, nonatomic) NSString *searchTerm; | |
@property (strong, nonatomic) NSError *error; | |
@property (assign, nonatomic) BOOL isLoading; | |
@property (strong, nonatomic) RACSubject *forceRestartServerRequestSubject; | |
@end | |
@implementation MMBaseReactiveSearchTableViewModel | |
- (instancetype)init { | |
if (self = [super init]) { | |
self.forceRestartServerRequestSubject = RACSubject.new; | |
RAC(self, searchResults) = [self.searchResultsSignal distinctUntilChanged]; | |
} | |
return self; | |
} | |
- (RACSignal *)searchResultsSignal { | |
@weakify(self) | |
RACSignal *latestSearchTerm = [[RACObserve(self, searchTerm) map:^id(NSString *searchTerm) { | |
@strongify(self) | |
if (searchTerm.length == 0) { | |
self.isLoading = NO; | |
return [RACSignal return:nil]; // so we immediately get an empty results table | |
} | |
return [[[RACSignal empty] delay:0.3] concat:[RACSignal return:searchTerm]]; | |
}] switchToLatest]; | |
// forceRestartServerRequestSubject has to start with nil because combineLatest needs at least one value | |
// to start working. | |
RACSignal *latestOrRefreshedSearchTerm = [RACSignal combineLatest:@[latestSearchTerm, [self.forceRestartServerRequestSubject startWith:nil]] reduce:^id(NSString *latestSearchTerm, id forceRefresh) { | |
return latestSearchTerm; | |
}]; | |
RACSignal *latestSearchResults = [[[latestOrRefreshedSearchTerm map:^id(NSString *searchTerm) { | |
// This ensures that we immediately switch to a new search term if it's empty, | |
// thus cancelling any running request for old search terms. An empty results table is immediately shown. | |
if (searchTerm.length == 0) { | |
return [RACSignal return:nil]; | |
} | |
@strongify(self) | |
RACSignal *serverResults = [[self serverSearchSignalWithSearchTerm:searchTerm] catch:^RACSignal *(NSError *error) { | |
// Catch server errors and return an empty result set | |
@strongify(self) | |
self.error = error; | |
return [RACSignal return:nil]; | |
}]; | |
// Return nil until the server results arrive, so the results table is emptied until results are there | |
return [[RACSignal return:nil] concat:serverResults]; | |
}] switchToLatest] doNext:^(id x) { | |
@strongify(self) | |
self.isLoading = NO; | |
}]; | |
return latestSearchResults; | |
} | |
- (void)forceRestartSearch { | |
[self.forceRestartServerRequestSubject sendNext:nil]; | |
} | |
// Override in subclass | |
- (RACSignal *)serverSearchSignalWithSearchTerm:(NSString *)term { | |
return [RACSignal return: nil]; | |
} | |
@end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment