需求分析:
用戶快速連續(xù)輸入時(shí),如果需要實(shí)時(shí)響應(yīng)用戶輸入。比如實(shí)時(shí)搜索,那么需要快速響應(yīng)輸入內(nèi)容,盡快地完成搜索任務(wù)。在服務(wù)器端,由于性能強(qiáng)大,只要網(wǎng)絡(luò)流暢,實(shí)時(shí)搜索并不是問(wèn)題。國(guó)內(nèi)的百度和國(guó)外的 Google 都能實(shí)時(shí)顯示搜索結(jié)果。但在移動(dòng)客戶端本地搜索時(shí),如果數(shù)據(jù)量大,在低端機(jī)型流暢地響應(yīng)實(shí)時(shí)輸入會(huì)比較困難。
實(shí)現(xiàn)方案:
一個(gè)2000條聯(lián)系人,外加總計(jì)人數(shù)5000左右的群聊成員的數(shù)據(jù)量大小。輸入完成,要流暢地顯示結(jié)果并匹配高亮輸入文案,要求從輸入完成到輸入下一個(gè)字符的不足1秒的時(shí)間內(nèi),完成搜索匹配。如果不能完成搜索,就會(huì)給用戶卡頓的感覺(jué)。其實(shí)不用在輸入文案每次變化都去進(jìn)行搜索,可以等待一定時(shí)間間隔再拿最新的輸入數(shù)據(jù),去進(jìn)行匹配。間隔低于指定時(shí)間間隔就忽略,控制搜索的頻率。在 iOS 端已經(jīng)有 Message Throttle 方案能夠?qū)崿F(xiàn)消息截流限頻。果斷引入,創(chuàng)建一個(gè) MTRule,然后應(yīng)用。

但是實(shí)際使用時(shí)發(fā)現(xiàn),快速輸入時(shí),有兩個(gè)問(wèn)題:
- 輸入卡頓
- 搜索的結(jié)果出現(xiàn)了大的延遲,有時(shí)甚至接近1分鐘
這個(gè)是不能忍受的,必須得解決。
輸入卡頓
明顯是輸入的主線程被阻塞。由于原來(lái)的實(shí)現(xiàn)都是在主線程進(jìn)行搜索,必須創(chuàng)建一個(gè)并發(fā)的全局隊(duì)列。然后將搜索封裝到 NSOperation 中,放進(jìn)隊(duì)列里。借助 《NSOperation 的進(jìn)階使用和簡(jiǎn)單探討 》這篇文章的分析,指定 queuePriority 為NSOperationQueuePriorityVeryHigh,以及 qualityOfService 為 NSQualityOfServiceUserInteractive。
然后等待搜索完成,切換回主線程,渲染 UI。
搜索結(jié)果延遲
在搜索任務(wù)里面,打印正在搜索的字符串,發(fā)現(xiàn) Message Throttle 并沒(méi)有起到作用,每一個(gè)字符輸入后,都會(huì)進(jìn)行一次搜索。
看來(lái)得在調(diào)用此函數(shù)前就限制,即提前截流。
但是仍然會(huì)有部分字符串進(jìn)行了多余的搜索,比如:
連續(xù)輸入: z h e n, 按照預(yù)期,只要執(zhí)行搜索: zhen 一次即可。
但實(shí)際上,還可能搜索了 zhe。
想到 NSOperation 有一個(gè) cancel 方法,可以在加入新的搜索任務(wù)前,取消之前的搜索任務(wù)。
高興地添加后,運(yùn)行發(fā)現(xiàn),還是會(huì)有部分多余搜索。詳細(xì)查看 API說(shuō)明,發(fā)現(xiàn):

原來(lái), cancel 方法不會(huì)取消正在執(zhí)行的任務(wù),由于是快速輸入,之前的搜索是來(lái)不及取消的。
仔細(xì)思考,突然腦洞一開,不管用戶輸入多么快,同一時(shí)刻輸入的文字是唯一的。在搜索任務(wù)時(shí),判斷下當(dāng)前最新的輸入內(nèi)容,與分配的搜索任務(wù)的字符串是否一致。如果一致,再進(jìn)行詳細(xì)的搜索匹配。否則,啥也不做。加了后,最終的實(shí)現(xiàn)方案如下圖。


小結(jié):
使用 Message Throttle ,實(shí)現(xiàn)了限制用戶輸入頻率的效果。使用 NSOperation 和 NSOperationQueue ,將搜索的任務(wù)分配到子線程,不影響交互。同時(shí)在搜索開始判斷當(dāng)前的最新輸入內(nèi)容是否與將要搜索的內(nèi)容一致, 一致再繼續(xù)搜索。
最終,實(shí)現(xiàn)了高頻輸入,絲滑般的體驗(yàn)?;旧显谟脩糨斎胂乱粋€(gè)字符前,能顯示搜索的結(jié)果。當(dāng)然,這也得益于搜索算法的高效。關(guān)于搜索匹配用到的拼音及拼音首字母匹配算法,詳見(jiàn) 《 iOS 字符串搜索匹配拼音或拼音首字母算法實(shí)現(xiàn)》。
有不足之處,歡迎指正。