In my app, I have a global C struct that holds colors:
//Colors.h
extern struct MYColors *appColors;
struct MYColors
{
CGColorRef appBackgroundColor;
// ...Lots more colors follow
};
And the matching implementation file:
//Colors.m
struct MYColors *appColors = calloc(1, sizeof(struct MYColors));
appColors->appBackgroundColor = CGColorCreateGenericRGB(23.0f/255.0f, 24.0f/255.0f, 26.0f/255.0f, 1.0f);
This allows me to centralize all my app's colors. In various custom views, I write code like this in Objective-C:
- (void) updateLayer {
someCGLayer.backgroundColor = appColors->appBackgroundColor;
}
I'm starting to migrate this app to Swift and I have not been able to figure out how I can access the imported version of this C Struct. I've seen lots of posts for simple structs that contain int
, float
, etc.
If I have a global instance (basically a singleton) of this struct, appColors
, how do I access the members of that struct from Swift?
This does not work. Swift claims that MYColors
has no appBackgroundColor
:
let color: CGColor = UnsafePointer<MYColors>(appColors).appBackgroundColor
I also thought maybe I just needed to access the singleton like this:
let color: CGColor = UnsafePointer<MYColors>(MyModuleName.appColors!).appBackgroundColor
But that does not work either.
The C declaration
extern struct MYColors * appColors;
is imported to Swift as
public var appColors: UnsafeMutablePointer<MYColors>!
Dereferencing a pointer is done in Swift via the pointee
property, so the Swift equivalent of the (Objective-)C code
appColors->appBackgroundColor
is
appColors.pointee.appBackgroundColor
The type of that value is Unmanaged<CGColor>!
because the Swift compiler does not know how the memory of the object should be managed. In your case the caller is not responsible for releasing the object, so the final code is:
let bgColor = appColors.pointee.appBackgroundColor.takeUnretainedValue()
For more information about unmanaged references, see Unmanaged
.
Remark: If appColors
and all struct members are guaranteed to be non-NULL when accessed then you can annotate them with _Nonnull
in the interface:
struct MYColors {
CGColorRef _Nonnull appBackgroundColor;
// ...
};
extern struct MYColors * _Nonnull appColors;
The Swift compiler then imports the variables as non-optionals instead of (implicitly unwrapped) optionals.