We're using frameworks instead of swift package modules. I'd like to define something like Bundle.module for each framework that I can use to access the localized strings, images, and other assets in the framework, methods which all take a bundle as a parameter.
Can I safely extend Bundle in each framework with a computed property of the same name without those properties interfering with each other in downstream targets that import both frameworks?
Framework Foo
extension Bundle {
static var module: Bundle {
Bundle(identifier: "inc.framework.Foo")!
}
}
public class FooClass {
public static var bundleId: String {
Bundle.module.bundleIdentifier!
}
}
Framewok Bar
extension Bundle {
static var module: Bundle {
Bundle(identifier: "inc.framework.Bar")!
}
}
public class BarClass {
public static var bundleId: String {
Bundle.module.bundleIdentifier!
}
}
Application
import Bar
import Foo
print(FooClass.bundleId) // prints "inc.framework.Foo"
print(BarClass.bundleId) // prints "inc.framework.Bar"
In fact this does what I want it to and prints the correct bundle identifiers, but I wanted to ask if this is safe to do and why it works?
Yes, this is fully safe and an intended behavior. You may be familiar with a problem in Objective-C where categories on a class that each introduce the same method will clash at runtime and cause non-deterministic behavior. This is not the case in Swift.
and why it works?
It works because though Bundle.module may share a name across two different modules, the name of each module is mangled into the final runtime name for the accessor - a compiler-aided solution to the namespacing problem above. You can see that in the code that results from compiling your sample code.
In the module Foo, Bundle.module has the mangled name s10Foundation6BundleC3FooE6moduleACvgZ
In the module Bar, Bundle.module has the mangled name s10Foundation6BundleC3BarE6moduleACvgZ
(run swift demangle on each of those mangled names)
Also it’s worth pointing out that this all continues to work even if the two Bundle.modules are public as well. The difference there though is if you import both modules and reference Bundle.module from an expression, the type checker will reject the expression with an ambiguity error.