Swift Protobuf – How to Implement

In 2008, a team in Google developed Protocol Buffers (ProtoBuf for short-name). Protobuf is faster and efficient than JSON/XML. In this tutorial, I am going to show you on how to implement this feature. You can view/download the source code at my GitHub page.

Tutorial Goal

Retrieve real-time service alerts from a transit agency’s service alert using Protobuf.

Installing ProtoBuf

Apple create a ProtoBuf library on their GitHub page. In this example, I have used Homebrew to install the library. If you don’t have Homebrew, please visit their website on how to install.

Open terminal and enter the following command to install Homebrew.

brew install swift-protobuf
Terminal window.

After installing swift-protobuf on your MacBook, create a new iOS project.

Create a new project and CocoaPods

Create a new project in Xcode. For this project, select Swift as your language and User Interface as Storyboard.

Creating a new iOS Single View App.
  • Product Name: service-alerts
  • Team: [your team]
  • Organization Name: [any name]
  • Language: Swift
  • User Interface: Storyboard
  • Everything else is unchecked

After creating a new project, close Xcode. Open Terminal and go to the project’s directory.

In Terminal, go to the project’s directory.

Create a Podfile by entering this in terminal:

touch PodFile

Open the Podfile by entering this command:

open -e PodFile

A notepad (or TextEdit) is opened and enter the following script:

use_frameworks!
target 'service-alerts' do
	pod 'SwiftProtobuf', '~> 1.7'
end

Note: Please check Apple’s Swift-Protobuf version number at their GitHub page. In this example, version 1.7 was used. However, if Apple revised their library to 1.8, change the 1.7 to 1.8.

Save the script and close the notepad. In terminal, enter the following command to install the framework:

Installation is competed.

Open the project’s folder and open the .xcworkspace file.

Development

Part A – Reading from a local

The first part of this tutorial is that the ProtoBuf will read a local object (not written in JSON). This tutorial is similar to Apple’s ProtoBuf GitHub page. However, the tutorial that I have written on this blog has more details. The Apple’s example is incomplete and can frustrate several beginner or junior iOS developers.

Create a new Protobuf file

Add a file by opening and right-click the project’s folder. Click “New File”.

Select “New” and press “Next”.

Save as DataModel.proto and press “Create”.

Enter the following source code:

syntax = "proto3";

message BookInfo {
   int64 id = 1;
   string title = 2;
   string author = 3;
}

The next step is to compile this protobuf file using Terminal. Save the file and open terminal.

In Terminal, enter the following command to compile the protobuf:

protoc --swift_out=. DataModel.proto
This command will compile the Protobuf file and convert to Swift format.

Press the “Return” key to compile. After compiling the file, go to the project’s folder and you will see a file was created.

A Protobuf file was converted to a Swift file.

Add that file to the project’s navigator.

Open the ViewController.swift file. At the header, enter a new header:

import SwiftProtobuf

Inside the viewDidLoad() method, enter the following source code below the super.viewDidLoad()

// Create a BookInfo object and populate it:
        var info = BookInfo()
        info.id = 1734
        info.title = "Really Interesting Book"
        info.author = "Jane Smith"

        // As above, but generating a read-only value:
        let info2 = BookInfo.with {
            $0.id = 1735
            $0.title = "Even More Interesting"
            $0.author = "Jane Q. Smith"
          }

        do {
            // Serialize to binary protobuf format:
            let binaryData: Data = try info.serializedData()
            
            // Deserialize a received Data object from `binaryData`
            let decodedInfo = try BookInfo(serializedData: binaryData)
            print(">>>>>>>>>>>")
            print(decodedInfo)
            
            // Serialize to JSON format as a Data object
            let jsonData: Data = try info2.jsonUTF8Data()
            // Deserialize from JSON format from `jsonData`
            let receivedFromJSON = try BookInfo(jsonUTF8Data: jsonData)
            print(">>>>>>>>>>>")
            print(receivedFromJSON)
        } catch {
            print(error)
        }

Run the application and you should see the data at the debugger.

Part B – Reading from an API

In this example, I am going to use a GTFS-Real Time feed called Service Alerts. Service Alerts notifies the passengers about if a bus or other transit vehicle is having issues. Also, service alerts is displayed on Google Maps (when planning a transit trip).

Download the GTFS Realtime Protobuf file at Google Transit APIs (since we don’t know what is the variable…only Google knows)

Open Terminal and compile the gtfs-realtime.proto file.

protoc --swift_out=. gtfs-realtime.proto

And then place gtfs-realtime.pb.swift file to your project.

Source Code

Open the ViewController.swift file. Get your own token-key at this transit agency developer portal. After getting your own token key, insert the following source code:

func readAlerts(){
        let request = URLRequest(url: URL(string:"https://api.ridemetro.org/GtfsAlerts/Alerts?subscription-Key=***********")!)
        
        print(request)
        
        URLSession.shared.dataTask(with: request) { (data, _, _) in
            // custom type
            
            guard let response = try? TransitRealtime_FeedMessage(serializedData: data!) else {
                // error
                return
            }
            //print(response)
            
            guard let receivedFromJSON = try? TransitRealtime_FeedMessage(jsonUTF8Data: response.jsonUTF8Data()) else{
                return
            }
            print(receivedFromJSON)
        }.resume()
    }

And you’re done. The next tutorial, I will show on how to output the Protobuf data to a table.

Project file

You can view/download the project at my GitHub page.