Efficient Data Transfer in iOS Apps: Exploring HTTP Compression

Β·

3 min read

Optimizing performance and reducing data costs are essential for any iOS app. One way to achieve this is through HTTP compression, which reduces the size of data transferred between an app and a server by compressing the request and/or response messages. By implementing HTTP compression in your iOS app, you can significantly improve its load times, reduce bandwidth usage, and provide a better user experience overall.

In this blog post, you learn about HTTP compression and how to apply it for either HTTP requests or responses in iOS app development with coding examples.

HTTP compression in a nutshell

HTTP compression is often associated with HTTP data being compressed before it is sent from the server. However, clients can also compress data before being sent to the server.

TypeClient TaskiOS Support
Request compressionCompress data to be sent to the serverManual
Response compressionUncompress data received by the serverOut-of-the-box

There are various compression algorithms. The most commonly used is gzip which I will use in my examples.

I do not go into details about the server-side implementation, but you can use the following Python script to create a Flask web server for testing HTTP compression.

from flask import Flask, request, Response
import gzip
import io

app = Flask(__name__)

@app.route('/')
def compress():
    # Create some sample data
    data = "Hello, world!".encode('utf-8')

    # Compress the data
    compressed_data = io.BytesIO()
    gzipper = gzip.GzipFile(fileobj=compressed_data, mode='wb')
    gzipper.write(data)
    gzipper.close()
    compressed_data.seek(0)

    # Return the compressed data as the response
    return Response(compressed_data.getvalue(), mimetype='application/octet-stream', headers={'Content-Encoding': 'gzip'})

@app.route('/upload', methods=['POST'])
def decompress():
    data = request.get_data()
    # Decode the gzipped data
    compressed_data = io.BytesIO(data)
    gzipper = gzip.GzipFile(fileobj=compressed_data)
    decompressed_data = gzipper.read().decode('utf-8')
    return decompressed_data

if __name__ == '__main__':
    app.run(debug=True)

HTTP Request Compression

Imagine you must upload a 7.4 MB JSON document. Using gzip to compress the data would only require transferring 1.7 MB with a default compression rate.

As an app developer, you must

  • set the Content-Encoding header and

  • compress the data

Setting the header is easy

request.setValue("gzip", forHTTPHeaderField: "Content-Encoding")

What about compressing the data? Apple ships zib and its higher-level Compression framework, but I was surprised that there is no easy way to use gizp.

Thankfully two open-source projects provide this functionality:

  • 1024jp/Gzip: Written in Swift this framework provides Data extension to enable compressing/decompressing gzip using zlib.

  • nicklockwood/GZIP: Written in Objective-C this framework provides NSData category for gzipping/unzipping data.

Using 1024jp/Gzip makes compressing the data super easy

import Gzip // introduced Data.gzipped(level:)

request.httpBody = try! data.gzipped() // compression

Here is a complete example of using 1024jp/Gzip

import Gzip // introduced Data.gzipped(level:)

let data = "Hello, World".data(using: .utf8)! // imagine a large JSON or file

let endpoint = URL(string: "http://www.example.com")!
var request = URLRequest(url: endpoint)
request.httpMethod = "POST"
request.httpBody = try! data.gzipped()
request.setValue("gzip", forHTTPHeaderField: "Content-Encoding")
try await URLSession.shared.data(for: request)

Admittedly HTTP request compression is not a typical scenario to be supported by servers. Some even discourage the use of HTTP request compression because the server can be attacked by zip/compression bombs.

Nevertheless, if your server supports it and you need to upload a large amount of information, then it is good to know how HTTP request compression can be done in Swift.

HTTP Response Compression

You might have used response compression without even knowing it. Because Apple's Foundation framework provides out-of-the-box support with URLSession.

When sending an HTTP request URLSession automatically adds an Accept-Encoding header.

When receiving an HTTP response URLSession automatically uncompresses the data.

let endpoint = URL(string: "http://www.example.com")!
var request = URLRequest(url: endpoint)
let (uncompressedData, response) = try await URLSession.shared.data(for: request)

Did you find this article valuable?

Support Marco Eidinger by becoming a sponsor. Any amount is appreciated!