Blog

Efficient Way for Search by Text in iOS and Flutter

By 29 January 2021 No Comments

Efficient Way for Search by Text in iOS and Flutter

How to perform search by text in iOS and flutter

Sharing is caring!

Search by Text is the most common feature in almost every mobile application. It’s necessary to make it efficient in a way that the search operation should be performed only when the user stops typing for a second or half of the second. For example, the search field when edited, performing network operation to retrieve data from the server via API. It’s bad practice to make API requests upon each word change. User might want to search for a specific word, so let him type that word and then we make API requests when the user pauses for a while. We know smart users type very fast! 

Have a look at the example here. I’ve visited an online mobile shopping app and want to search the term ‘iPhone’. Search  function of the app is like it takes the word typed in the field by the user, makes an API request to query for results from the server. So there will be API requests hitting one after another as I type, and so for the term ‘iPhone’ 5 API request will be made. That’s definitely a bad practice. 

Perform Search Operation with Timer  

A basic logic to make our search more efficient is to put our code for search operation inside the Timer function. I’ve created a dedicated class named ‘DelayedRunner’ to handle all of these. Let’s jump directly to code. 

iOS – Swift

//  DelayedRunner.swift

import UIKit

class DelayedRunner
{
    private var seconds:Double = 500
    private var timer:Timer?

    static func initWithDuration(seconds:Double) -> DelayedRunner {
        let obj = DelayedRunner()
        obj.seconds = seconds
        return obj
    }
    
    func run(action: @escaping (()->Void)) {
        if(timer != nil){
            timer?.invalidate()
            timer = nil
        }
        timer = Timer .scheduledTimer(withTimeInterval: seconds, repeats: false, block: { (t) in
            action()
        })
    }
}

Usage:

private let runner = DelayedRunner.initWithDuration(seconds: 0.5) 
...
... 
func searchFieldTextChanged(_ sender: UITextField) { 
    if let text = sender.text { 
        runner.run { 
           //Perform API request 
        } 
    } 
} 
  1. We create an instance of DelayedRunner – runner, with seconds = 0.5. 
  2. On text change in search field, instead of directly calling API we call it within runner.run() 
  3. Runner.run() implementation shows that it should cancel any scheduled operation with a timer and start a new one. 

This way as the user types fast, timer cancels each past scheduled operation and performs only if there is pause of 0.5 second. The same logic implies to flutter: 

Flutter

I’ve applied the same logic in one of my Flutter projects, the class name is the same: DelayedRunner.

//delayed_runner.dart

import 'dart:async';
import 'package:flutter/cupertino.dart';

class DelayedRunner
{
  final int milliseconds;
  VoidCallback action;
  Timer _timer;

  DelayedRunner({this.milliseconds});

  run(VoidCallback action) {
    if (null != _timer) {
      _timer.cancel();
    }
    _timer = Timer(Duration(milliseconds: milliseconds), action);
  }
}

Here also timer’s scheduled operation gets cancelled if the user’s typing speed is less than 500 milliseconds per character. 

Usage:

final _runner = DelayedRunner(milliseconds: 500); 
...
... 
TextField( 
    controller: _searchController, 
    onChanged: (text){ 
          _runner.run((){ 
               //Perform search operation / API request 
          }); 
    }, 
); 

Get started with Bloom