Calling Go code from Swift on iOS and vice versa with Gomobile

Gomobile lets you turn a Go package into a Framework that can be imported into a Swift application which allows you to call Go code from Swift, and vice versa.
Most online tutorials focus on calling Go from Swift, and not the other way round but if we are to really use Go to build out the bulk of our iOS applications, this is a vital ingredient. It took me several hours to get it right thanks to the temperamental nature of Xcode mixed with my lack of understanding of Gomobile, so this tutorial presents a solution that is repeatable (by me) and hopefully useful to you too.
This tutorial will cover:
- Common errors or unexpected blockers (search for GOTCHA throughout this post to highlight these), and how to overcome them
- Calling a Go constructor in Swift to create an instance of a Go struct
- Define an interface in Go that we want our Swift code to implement
- Pass the Swift implementation to the Go constructor, and initiate two-way communication
You will need:
- A mac — I’m running macOS Sierra 10.12.6 (16G29)
- A text editor — I use Visual Studio Code
- Xcode — I have version 8.2 (8C38)
- Go installed
- Gomobile installed and setup — see this tutorial for how to get setup
Structure
Let’s start with a simple folder structure so we can discuss the constituents of our project.
Somewhere inside your $GOPATH, create a folder called gomobiletest and add the following subfolders:

- The
frameworksfolder is where we’ll put the framework that Gomobile generates for us - The
gofolder will contain our Go code, and thegreeterpackage is where our business logic will live - The
iosfolder is where we’ll create our Swift project later
In this tutorial, we are going to build an iOS Framework from our greeter package.
Our Go package
Let’s start by building a simple Go package that lets us greet somebody.
We will write:
- A constructor to create and return a struct type
- An interface for printing values, which we’ll implement in Swift
- A Go method on the struct that prepares the greeting and calls the method on the interface to print it out
To gomobiletest/go/greeter, add the following greeter.go file:
package greeter// Printer types can print things.
type Printer interface {
PrintSomething(s string)
}// Greeter greets people.
type Greeter struct {
printer Printer
}// NewGreeter makes a new Greeter.
func NewGreeter(printer Printer) *Greeter {
return &Greeter{
printer: printer,
}
}// Greet greets someone.
func (g *Greeter) Greet(name string) {
g.printer.PrintSomething(“Hello “ + name)
}
GOTCHA: Originally I named my Printer method Print, but once this gets translated into Swift it clashes with the builtin print function, and I ended up recursing forever. SOLUTION: Be careful with names; they might have to be slightly more verbose (PrintSomething vs Print) than we would like in traditional Go code so it doesn’t clash in Swift.
The above code is fairly simple; we create a Greeter with the NewGreeter function, taking in a Printer which we use later when sending the greeting. In Go we might omit the NewGreeter constructor, but we can’t in Gomobile because Swift code cannot instantiate Go objects.
In Gomobile, all memory allocation of the types must occur in the world where that type is defined.
Building the framework
Now our package is ready to go, it’s time to build the iOS framework that can be imported into our Swift project.
We are going to use the gomobile command to do this, specifically its bind feature. In a terminal, navigate to the gomobiletest/go/greeter folder and use the gomobile command to create the framework:
gomobile bind -target ios -o ../../frameworks/Greeter.frameworkAfter a few moments, you will notice that a new item has appeared in our frameworks folder called Greeter.framework.
You’ll notice that an iOS framework is actually just a folder full of stuff, including the Greeter binary. Take a moment to check out what was generated:

Peek at the Objective-C headers
Let’s have a quick look at the Objective-C headers for our framework (remembering that we’re not going to be using these). Open the Greeter.objc.h file:

This generated code describes the Objective-C objects that represent our Go greeter package. Notice specifically:
@protocol GreeterPrinter— this is ourPrinterinterface represented as a protocol
Did you know that protocols in Objective-C are actually the precursor to interfaces in Go? — Blaine Garst, who I have the privilege of calling a friend, cooked-up protocols (with Bertrand Serlet and Steve Naroff) when they worked at NeXT in 1990. You can read more about that in A Short History of Objective-C by Hansen Hsu.
- (void)printSomething:(NSString*)s— This line inside the protocol describes ourPrintSomethingmethod; the cases are mutated to match the iOS patternsFOUNDATION_EXPORT GreeterGreeter* GreeterNewGreeter(id<GreeterPrinter> printer)— This describes ourNewGreeterconstructor function
You will notice that all types are in the global namespace (rather than being encapsulated into a package) and are instead just prefixed with the package/framework name. This is the same in Swift so you should bear this in mind when naming things, and be sure to avoid clashes.
GOTCHA: Your package name must match the name of your framework. So
package greetermeans our framework must be calledGreeter.framework. Originally my package had a different name and it was failing without telling me why.
Create an iOS application
Now open Xcode and choose Create a new Xcode project. In the iOS tab, select Single View Application and click Next.

Be sure to select Swift as the language, and fill out the rest of the fields as you see fit. Mine looks like this:

Give your project a name (let’s stick with GoMobileTester for now) before finally clicking Next and then Create once you’ve navigated to the ios folder.
Importing a Gomobile framework
Now we are going to import our Greeter.framework so that we can interact with it in Swift. Open Finder, and navigate to the frameworks folder. Then drag the Greeter.framework file into Xcode at the bottom of the Project navigator. A dialog will open to confirm the action, be sure to check Copy items if needed.

GOTCHA: Some tutorials say that copying the framework is optional, but I couldn’t get it to work without doing so — let me know if you learn differently.
Click Finish and the framework should be added:

You will also notice that the framework has been added to the Link Binary With Libraries section of the Build Phases tab:

This is really what tells Xcode to bundle the framework with the iOS application.
Implementing a Go interface in Swift
Now that the framework is imported, let’s write the Swift implementation of the Printer interface we defined in Go.
Right-click the GoMobileTester folder (not the Xcode project at the top, the one below that), and choose New File... Select Cocoa Touch Class, and click Next. Call the class SwiftPrinter and make sure it’s a subclass of NSObject and click Next and then Create.
The skeleton class that Xcode creates for us looks like this:
import UIKitclass SwiftPrinter: NSObject {}
The first thing we are going to do is inform Swift that this object is going to implement the protocol (our Go Printer interface).
Update the code to import the Greeter framework and add the protocol to the list of things the SwiftPrinter inherits:
import UIKit
import Greeterclass SwiftPrinter: NSObject, GreeterPrinterProtocol {}
GOTCHA: The Objective-C objects actually has different names to the Swift objects, so if you’re using Swift, it’s better to completely ignore those Header files we looked at earlier, because they’ll only confuse things.
The actual protocol name is GreeterPrinterProtocol. The import Greeter line at the top ensures that this code file can access the objects inside the Greeter framework. Without it, we’d see an error complaining that it doesn’t know what GreeterPrinterProtocol is.
Inspect the generated Swift code
While holding Cmd+Shift, click on the GreeterPrinterProtocol protocol in the code and notice that we are taken to a new file that contains the Swift code. This is the Swift equivalent of the Objective-C code we looked at earlier, although the names are different:

Hit Cmd+B to build the project, and notice that we encounter an error:

It tells us that the SwiftPrinter does not conform to our protocol; which is fair enough.
Update the code adding the printSomething function:
import UIKit
import Greeterclass SwiftPrinter: NSObject, GreeterPrinterProtocol { public func printSomething(_ s: String!) {
print("This just in:", s)
}}
Build again (press Cmd+B) and notice that there are no errors.
Calling Go code from Swift
Now it’s time to call our Go constructor from Swift. The simplest place to do this is in the ViewController.swift file, just after the default view is loaded.
First, add the same import to the top of the file:
import UIKit
import GreeterNext, inside the viewDidLoad function, let’s first prepare the Printer argument that our NewGreeter function expects:
override func viewDidLoad() {
super.viewDidLoad() let printer = SwiftPrinter()}
So the printer variable will be an instance of the SwiftPrinter we just made.
Now let’s create a Greeter (actually in Swift it’s a GreeterGreeter):
override func viewDidLoad() {
super.viewDidLoad() let printer = SwiftPrinter()
let greeter = GreeterNewGreeter(printer)}
So our greeter variable will be an instance of the Greeter type (that we wrote in Go) and the Printer interface will be satisfied by our printer variable, which is an object that implements the appropriate protocol.
Finally, let’s just call the greet method:
override func viewDidLoad() {
super.viewDidLoad() let printer = SwiftPrinter()
let greeter = GreeterNewGreeter(printer)
greeter!.greet("Mat")}
Step-by-step, here’s what’s going on:
- Swift: iOS application calls
viewDidLoad - Swift: We create a
SwiftPrinter, and useGreeterNewGreeterto create a newGreeter, passing in theprinter - Go:
NewGreetercreates a newGreeterobject (saving theprinteras a field so we can access it later), and returns it - Swift: We save the returned
GreeterGreeterin thegreetervariable (strange name; remember it’s the package name and the struct name combined) - Swift: We call the
greetmethod on thegreeter, passing in a name - Go: Accessing the
printer, we call thePrintSomethingmethod, by concatenatingHelloand the passed-in name - Swift: The
SwiftPrintertype’sprintSomethingmethod is called, where we print outThis just in:with the greeting string - Finally, the string should be printed to the console via the built-in
printmethod
No Bitcode
Press Cmd+B again and notice that we get an error.

Thanks Xcode, that’s very easy to deal with!
Seriously, this is a great example of why Go and its toolchain win over Swift and its toolchain in my opinion — although you do get used to Xcode the more you work with it.
If you read carefully and haven’t already taken your own life, you will notice that it says this:
...framework does not contain bitcode. You must rebuild it with bitcode enabled (Xcode setting ENABLE_BITCODE), obtain an updated library from the vendor, or disable bitcode for this target.Gomobile doesn’t support Bitcode right now, so we will take this advice and go and disable it.
GOTCHA: You must disable Bitcode for any application that imports a Gomobile framework.
In the Project navigator, select the topmost GoMobileTester project item, and select the Build Settings tab. Type bitcode in the search bar and change the Enable Bitcode setting to No:

Build again by pressing Cmd+B and notice this time that it builds successfully.
Running the solution

Select an iPhone simulator from the toolbar (top left) and press the play (run) button.
After a moment or two, the simulator will startup and the code will execute.
Click the middle button from the group of window controls in the top right of Xcode to open the console:

We did it
Eventually you’ll see this message in the console in Xcode:

We have just successfully called Go code from Swift, and had a Swift method called by Go. 👍
Conclusion
We have successfully solved two-way communication between Swift and Go. Which means, in theory, you can build any kind of application you like.
But be careful, Gomobile is still very young and there are some limitations that you need to be aware of as you design your solution.
The remainder of this article will discuss limitations, as well as other ideas that might increase the chances of success.
Not all types are supported
Currently some types (like slices) are not supported by Gomobile, so you’ll have to wrap things in structs and methods. This is a pain, because your Go code ends up looking very non-Go, and if you have other customers for your code, you might end up with a pretty ugly and hard to use package.
It is assumed that slices will end up being supported by Gomobile, so this might be a temporary thing.
- For more information about this read about Supported Go types for Android with gomobile bind by Alex Pliutau
Bridging?
You might consider writing a bridge package that sits between your idiomatic Go code, and your Swift code. This bridge package would become the framework that gets imported.
In the bridge package, you could present the bare minimum capabilities that you want including in your package, and don’t have to worry about unsupported features from the rest of the code.
And you could build some method based slice abstraction without ruining your original Go code.
Keep up Xcode
Xcode tries to help keep things quick by caching a lot. This means, that if you change your framework API (say you rename the Greet method to SendGreeting) you might struggle to get Xcode to recognise the changes. I managed to get around this by creating a new Xcode project each time, but obviously as you get further down a project, that’s not a great solution.
You might want to try updating the framework in place.
Update in place
Instead of having a frameworks folder at all, you could ask the gomobile tool to put the output directly into the Xcode project. You can do this just by figuring out the appropriate path, like this:
gomobile bind -target ios -o ../../ios/GoMobileTester/Greeter.frameworkThis way, whenever you rebuild your framework, it’ll update the files directly.
What next?
- Build something awesome
- Browse the Gomobile documentation
- If you like the style of this tutorial and want to build more things in Go, then please consider buying my book Go Programming Blueprints: Second Edition.
