使用ReactiveCocoa優(yōu)化實時搜索

需求

在搜索中輸入任何文字,立即聯(lián)想到相關的搜索關鍵詞,以列表的方式進行顯示

最簡單的解決方案步驟:

  1. 監(jiān)聽輸入框文字的變化.
  2. 在回調(diào)中發(fā)起網(wǎng)絡請求
  3. 將請求的結(jié)果顯示出來

問題

  1. 在用戶輸入比較快的情況下,前面幾個請求只是在浪費用戶的流量,因為請求的結(jié)果會立即被覆蓋
  2. 由于網(wǎng)絡的不確定性,可能后請求的接口要晚于早請求的結(jié)果得到返回結(jié)果

使用ReactiveCocoa

針對問題1. 解決的辦法是限流:

    /// 問題1解決
    self.throttleSubject = [RACSubject subject];
    [[self.throttleSubject throttle:1] subscribeNext:^(id x) {
        [self requestWithKeyWord:x];
    }];
    /// 模擬搜索框輸入
    dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.1 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
        [self.throttleSubject sendNext:@"1"];
    });
    
    dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.5 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
        [self.throttleSubject sendNext:@"2"];
    });

    dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.6 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
        [self.throttleSubject sendNext:@"3"];
    });
    
    dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
        [self.throttleSubject sendNext:@"4"];
    });

打印的結(jié)果是3,4
原理:在限流的時間內(nèi),如果沒有新的數(shù)據(jù)過來,時間到了,就會sendNext數(shù)據(jù),否則,釋放上個計時器(計時器也是個信號,通過dispose進行無效化),重新設置一個新的計時器倒計時
針對問題2.

    /// 問題2解決
    self.requestSignal = [RACSubject subject];
    [self.requestSignal.switchToLatest subscribeNext:^(id x) {
        NSLog(@"請求結(jié)果 : %@",x);
    }];

原理:switchToLatest這個信號內(nèi)部會在收到新的信號時候,將上一個信號進行釋放,也就是說在A,B兩個網(wǎng)絡請求信號,按順序請求的話,如果在B請求前,B請求已經(jīng)結(jié)束,那么,沒有任何問題,這時候搜索的內(nèi)容和關鍵字肯定還是匹配的,如果B請求的時候,A還沒有sendNext|sendComplete那么,會將A信號進行dispose掉,這樣即使A信號得到數(shù)據(jù)了也會return掉

- (void)sendNext:(id)value {
    if (self.disposable.disposed) return;
        .......
}

其實這個時候比較好的網(wǎng)絡請求代碼如下

- (RACSignal *)requestWithKeyWord:(NSString *)keyword {
    if (keyword.length == 0) return nil;
    return [RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) {
        AFHTTPSessionManager *manager;
        NSURLSessionDataTask *task = [manager POST:nil parameters:nil progress:nil success:nil failure:nil];
        return [RACDisposable disposableWithBlock:^{
            /// 此處可以中斷網(wǎng)絡請求
            [task cancel];
        }];
    }];
}

這樣會使得信號在被新的網(wǎng)絡請求信號沖刷掉的時候,及時終止網(wǎng)絡請求,節(jié)省資源.
完整代碼

- (void)testThrottle {
    /// 問題2解決
    self.requestSignal = [RACSubject subject];
    [self.requestSignal.switchToLatest subscribeNext:^(id x) {
        NSLog(@"請求結(jié)果 : %@",x);
    }];

    /// 問題1解決
    self.throttleSubject = [RACSubject subject];
    [[self.throttleSubject throttle:1] subscribeNext:^(id x) {
        NSLog(@"keyword : %@",x);
        [self.requestSignal sendNext:[self requestWithKeyWord:x]];
    }];
    
    /// 模擬搜索框輸入
    dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.1 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
        [self.throttleSubject sendNext:@"1"];
    });
    
    dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.5 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
        [self.throttleSubject sendNext:@"2"];
    });

    dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.6 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
        [self.throttleSubject sendNext:@"3"];
    });
    
    dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
        [self.throttleSubject sendNext:@"4"];
    });
}

- (RACSignal *)requestWithKeyWord:(NSString *)keyword {
    if (keyword.length == 0) return nil;
    return [RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) {
        dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
            [subscriber sendNext:keyword];
        });
        return nil;
    }];
}
keyword : 3
keyword : 4
請求結(jié)果 : 4
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容