Skip to content

Instantly share code, notes, and snippets.

@manmal
Created January 23, 2015 16:02
Show Gist options
  • Save manmal/201a905b290f3e1e09f0 to your computer and use it in GitHub Desktop.
Save manmal/201a905b290f3e1e09f0 to your computer and use it in GitHub Desktop.
Reactive Search Table View Model
@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