我正在构建一个 UISearchController,用户将在其中键入用户名,应用程序将从 Web 服务获取结果。
我想在用户输入时限制请求以减少网络调用。使用 ReactiveCocoa 如何实现这一点?
class SearchResultsUpdater: NSObject, UISearchResultsUpdating {
func updateSearchResultsForSearchController(searchController: UISearchController) {
let text = searchController.searchBar.text
let dataSource = searchResultsController.tableView.dataSource as! ...
}
}
最佳答案
实际上用 ReactiveCocoa 是解决这个问题的好方法。
您想在用户键入时获取文本,或者在“响应式(Reactive)”字词中您想要输入文本的“流”,如果您的用户是快速打字者,您希望仅在搜索文本未更改时才向服务器执行请求在短时间内,您可以自己完成(使用 Delegate、NSTimer),但是 ReactiveCocoa 非常简单且可读。
@property (weak, nonatomic) IBOutlet UISearchBar *searchBar;
[[textSignal throttle:0.4]subscribeNext:^(NSString* searchText) {
[[SearchService sharedInstance]search:searchText completed:^(NSString *searchResult, NSError *error) {
NSLog(@"searchResult: %@",searchResult);
}];
}];
假设您的类 SearchService 在 2.5 秒后返回 searchText 和 searchText 长度。
@implementation SearchService
typedef void(^CompletedResults)(NSString *searchResult, NSError *error);
- (void)search:(NSString *)text completed:(CompletedResults)handler {
NSString *retVal = [NSString stringWithFormat:@"%@ = %@", text, @([text length])];
// Here you should to do your network call and and return the response string
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
[NSThread sleepForTimeInterval:2.5];
if (handler){
handler(retVal, nil);
}
});
}
只需一行代码,您就可以限制输入文本。
其实ReactiveCocoa并没有提供UISearchBar的类,但是实现起来没那么复杂(可以找UISearchBar(RAC)类hire)
您要问自己的一个重要问题是,如果您已经向服务器发送了请求,并且在您得到答复之前用户继续输入,会发生什么情况? 您可能想取消先前的请求(并释放所有资源)并使用新的搜索文本向服务器发送新请求。 同样,你可以自己做,但使用 ReactiveCocoa 非常简单,只要你开始将事物视为信号。
您应该包装从服务器返回结果“流”的搜索服务。
@implementation SearchService
- (RACSignal *)search:(NSString *)text {
return [RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) {
[self search:text completed:^(NSString *searchResult, NSError *error) {
[subscriber sendNext:searchResult];
[subscriber sendCompleted];
}];
return nil;
}];
}
现在您所要做的就是将每个搜索文本映射到来自服务器的结果信号并调用 switchToLatest。
[[[[textSignal throttle:0.4]
map:^id(NSString* searchText) {
return [[SearchService sharedInstance]search:searchText];
}]
switchToLatest]
subscribeNext:^(NSString* searchResult) {
NSLog(@"searchResult: %@",searchResult);
}];
还有一件事,可能是当您从您想要更新 UI 的服务器获得响应时。而且你必须在主线程上进行。 同样这里使用 ReactiveCocoa 非常简单,只需添加 deliverOn:RACScheduler.mainThreadScheduler。
[[[[[textSignal throttle:0.4]
map:^id(NSString* searchText) {
NSLog(@"Get Text after throttle");
return [[SearchService sharedInstance]search:searchText];
}]
switchToLatest]
deliverOn:RACScheduler.mainThreadScheduler]
subscribeNext:^(NSString* searchResult) {
if ([NSThread isMainThread]){
NSLog(@"is MainThread");
}
else{
NSLog(@"is not MainThread");
}
NSLog(@"searchResult: %@",searchResult);
}];
祝你好运:)
如果您使用 Swift 编写代码,请查看 ReactiveSwift GitHub - Swift 的响应式扩展,受 ReactiveCocoa 启发
关于ios - UISearchResultsUpdating w/ReactiveCocoa,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/29976767/