on
Bridging Rust to Swift, pt. 5: Swift Packages, the final wrap
In our last post, we built a
Swift package that made distributing and using our .xcframework
a lot easier.
We will now tackle making our interaction with the C library more in line with
Swift principles.
The major sticking points we found while using our C API in the last post were
- Structs and their associated functions were decoupled.
- Working with
OpaquePointer
s was a bit cumbersome. - We had to manually manage memory.
One class to rule them all
All the aforementioned issues can be tackled by writing a single Swift class
SwiftPerson
. Our Swift package already has a file SwiftPerson.swift
with the
necessary boilerplate code. By default, the generated SwiftPerson
declaration
will be of type struct
- we need to change that to class
. We make this
change as we can’t have a deinitializer in a struct
.
We will have the class manage a single OpaquePointer
to a C struct Person
.
When the class is deinited in Swift, it will automatically free the memory
allocated in C. Finally, it will encapsulate all the C functions that interact
with the struct.
Let’s break this code down
- We first declare a variable to reference our
OpaquePointer
. - In our init, we create a C struct
Person
and assign the returnedOpaquePointer
toperson_op
. - Finally, in the
deinit
, we make sure that we always free the memory that was allocated in C duringinit
.
To complete our API encapsulation, we need a way to access the age on Person
.
We can do this by either an associated function in Swift or a computed property.
Computed properties feel a bit more natural in this instance.
The computed property hides the mechanics behind the working of the
OpaquePointer
. We now have a perfectly usable Swift class SwiftPerson
that
encapsulates our C struct Person
. Our final class definition reads as
The C API (and it’s existence) is completely hidden from the users of our
package SwiftPerson
, who can now do
Much simpler (and safer). This concludes our simplistic introduction to bridging rust/C to swift. However, once we get down to it, there are other topics that would require us to put our thinking caps back on - essentially around handling more complicated data structures and strings. Perhaps, another post for another day…