Rate Limiting on iOS

Whenever you enter an address into Google Maps or search for a video on YouTube, you may have noticed that the auto-complete suggestions update at regular intervals rather than with every change to the search query.

When you consider the scale of these platforms, limiting requests in this manner is a necessary optimization. This helps prevent unnecessary HTTP requests while still ensuring a smooth user experience.

Today, we'll look at a simple implementation you can use to replicate this behavior in your applications.

Let's continue with our auto-complete suggestions use case and imagine we have a function that makes an asynchronous HTTP request and returns an updated list of suggestions:

func getAutocompleteSuggestions(from query: String,
                                completion: (([String]) -> Void)?)

Ideally, we would like to be able to call this function directly within the delegate callback of our searchBar or textField and have some other mechanism that guarantees the request fires only once every X seconds.

Implementation

We can create the following ThrottleExecution utility to handle these requirements:

struct ThrottleExecution {

    private static var previousExecution = Date.distantPast

    static func execute(minimumInterval: TimeInterval, queue: DispatchQueue, _ block: @escaping () -> Void) {
        if abs(previousExecution.timeIntervalSinceNow) > minimumInterval {
            previousExecution = Date()
            queue.async { block() }
        }
    }

}

This method ensures that the block is only executed once in the TimeInterval specified. So, if this method is called 100 times within 9 seconds and we were to pass 5 seconds as the minimumInterval, the block will only be executed twice; the first time the method is called and once more 5 seconds later.

Usage

With just this simple ThrottleExecution utility we can effectively limit the execution frequency and customize the DispatchQueue of any task in our application:

ThrottleExecution.execute(minimumInterval: 0.3, queue: .main) { [weak self] in
    guard let self = self, let query = self.searchTextField.text else { return }

    self.getAutocompleteSuggestions(from: query) { searchSuggestions in
        // Update UI with new searchSuggestions
    }
}

If you're interested in more articles about iOS Development & Swift, check out my YouTube channel or follow me on Twitter.

If you're an indie iOS developer, make sure to check out my newsletter:

Indie Watch
Indie Watch is an exclusive weekly hand-curated newsletter showcasing the best iOS, macOS, watchOS, and tvOS apps from developers worldwide.

I feature a new developer every issue, so feel free to submit your indie iOS apps!


Do you have an iOS Interview coming up?

Check out my book Ace The iOS Interview!


Subscribe to Digital Bunker

Don’t miss out on the latest issues. Sign up now to get access to the library of members-only issues.
[email protected]
Subscribe