I'm currently trying to figure out how to setup the deployment target of my SFSafeSymbols framework. While doing this, I came across a general Swift topic: Weak linking of frameworks. Before sharing my thoughts about this in general, I'm going to shortly explain the situation with my framework.
The issue with SFSafeSymbols
The framework provides both an
enum making the SF Symbols in iOS 13 safely accessible and
convenience initializers leveraging this
Although the SF Symbols are an iOS 13 feature, users may want to import the framework and then use it if iOS 13 is available. This is why I initially set the framework deployment target to iOS 10. So far, so good. Now, just recently, an initializer for
SwiftUI.Image was added to my framework. As
SwiftUI is only available for iOS 13+ (which must be ensured at compile time), I had to bump the deployment target to iOS 13. If an app e. g. targeting iOS 12+ wants to import the framework now, there's of course an error, as the framework requires iOS 13+ – that makes sense. However, it leaves me surprised to learn there's no way to "conditionally" import this framework.
Weak linking of frameworks
With Objective-C, it's possible to make frameworks optional, as described here. However, there doesn't seem a similar feature for Swift, at least I didn't find anything about it anywhere. A SO question about this has remained unanswered for over two years.
If my research was right and there's actually no way to do this in Swift, I propose to introduce a safe way to do this. I could imagine to always allow the import of a framework marked as
Optional in Xcode:
import SFSafeSymbols // possible without availability check
However, when accessing types from this framework, it must be ensured that it was actually imported. It would be nice to infer this automatically based on an os version availability check, but there's probably a need for a dedicated check:
#if isAvailable(SFSafeSymbols) _ = SFSafeSymbol.circle.toImage // Use framework #endif
What do you think about such a feature? Are there other ways to achieve what I want (apart from splitting my framework into multiple sub frameworks)? Does such a feature fit Swift's design?