Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Nested class has unstable name. Fix with @objc with strange param

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?

like image 560
bauerMusic Avatar asked Jan 04 '23 04:01

bauerMusic


2 Answers

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).

like image 101
Hamish Avatar answered Jan 09 '23 06:01

Hamish


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

like image 30
Andrés Pizá Bückmann Avatar answered Jan 09 '23 04:01

Andrés Pizá Bückmann