Is there a possibility to implement a private API? In Objective-C there is the private module map. So you can (more or less) "hide" classes and methods from the client.
You can read the Access Control in the Swift Programming Language Guide.
There's an experimental annotation you can apply to public methods, @_spi
.
public struct MyStruct {
public init() {}
@_spi(Private) public func myPrivateFunc() {}
}
Clients that just import ThisFramework
will have access to MyStruct
and MyStruct.init
, but if they want to call myPrivateFunc
, they need to annotate their import with a corresponding @_spi
annotation with the same Private
"SPI tag"
@_spi(Private) import ThisFramework
let s = MyStruct()
s.myPrivateFunc()
You can use whatever SPI tag you'd like, and you can use as many as you'd like within the module.
Wow, this is exactly what I was looking for. Thank you very much @harlanhaskins! I will try this out!
I have two more questions. Does this also work with classes? And can I access the annotated method from another framework?
Because I have implemented several frameworks that partially access each other. Some methods and classes should only be used internally and my customers should not see/use them.
Yep, it works with any public
declarations.
Are these binary frameworks? If so, these declarations are only added to a .private.swiftinterface
file and the compiler will prefer to import that file if it's present, rather than the .swiftinterface
file. It may require an extra preprocessing step to remove this file from your built framework directory. There's an Xcode build setting to control whether this file is emitted, SWIFT_EMIT_PRIVATE_MODULE_INTERFACE
, but I am not sure how to conditionally set that build setting only when archiving.
My own app imports the normal frameworks. However, I want to provide it to my customers as a binary Swift Package. So I'll have to look into that with the .private.swiftinterface
. Thank you very much for your very helpful answers.
I now had the time to test the @_spi
annotation and it worked great with your instructions.
Though I noticed that I can still access the annotated method in Objective-C without any problems. @harlanhaskins do you know more about this? Is the annotation to be supported in Objective-C in the future or is it just a Swift thing?
I am not sure what the future plans are for ObjC, but it's a common request. @xymus, is this the kind of thing where we could like, guard these declarations with #ifdef SWIFT_<tag>_SPI
in the -Swift.h
header?
This would be very useful for the project that I am working on. Are there any plans to bring the @_spi
attribute out of the experimental phase and available as a supported annotation?
Hi, I don't see it in the Xcode build settings. Is this also a private setting, or no longer valid?