We have some code where a class is nested in an extension. After opening the project in Xcode 9, we get the 'Nested class has unstable name' warning.
When using Xcode auto-fix, it generate an @objc
with some (generated?) param.
For example:
struct Something {
}
extension Something {
@objc(_TtCV16MyProject9Something4Some) class Some: NSObject, NSCoding {
required init?(coder aDecoder: NSCoder) {
}
func encode(with aCoder: NSCoder) {
}
}
}
All this compiles. But what the heck is this _TtCV16MyProject9Something4Some
?
It seems to be unique because if we use the same one in two places, it will not compile (some generic project level compiler error).
If I replace the _TtCV16MyProject9Something4Some
with anything else (say @objc(Something)
), the project compiles fine, but that does not shad any more light really.
One important question, is the param randomly generated or is it an actual link to a real bridging name?
But what the heck is this
_TtCV16MyProject9Something4Some
?
It's the (Swift 3) mangled name for Something.Some
. And as you haven't specified a custom name by which to expose the class to Objective-C, it is also the name by which the Obj-C runtime sees the class (as Obj-C has no concept of nested classes).
Therefore it's also the name that is encoded into an NSCoding
archive of an instance of that class (allowing the instance to be re-constructed on decoding; the Obj-C runtime will be queried for the class that goes by that name).
The reason why you're getting this error is because name mangling for nested classes changed between Swift 3 and 4 – and may well change again in the future (until Swift is ABI stable at least). Therefore to allow archives encoded with Swift 3 mangled names to be decoded in Swift 4 and above, the compiler is suggesting you expose the class to Obj-C with the Swift 3 mangled name.
If you don't need to provide this backwards compatibility for Swift 3, then you can go ahead and expose the nested class to Obj-C with your own stable name (to ensure future mangling changes don't affect archive decoding). In this case, I would recommend something like @objc(Something_Some)
.
I think your class' name might contain a character not supported by Objective-C. In those cases, you can use the @objc(name)
attribute to provide an alternative name to use in Objective-C, and what you are seeing is an autogenerated unique name. This is also why you can change that with anything you like and it will compile just fine.
There's a section in Apple's docs explaining this, Configuring Swift Interfaces in Objective-C in https://developer.apple.com/library/content/documentation/Swift/Conceptual/BuildingCocoaApps/InteractingWithObjective-CAPIs.html#//apple_ref/doc/uid/TP40014216-CH4-ID55
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With