The other thing I can think of that’s common is to return an invalid value. For a price, all valid values are positive, so you could use -1 to indicate that the price is unknown or absent, for example. This is probably the most idiomatic approach of the three.
Currently I am using number for @objc and another computed variable for swift type. Is that similar to your approach or does "__" have special meaning?
Yes, they are different variables. But only one of the provides storage and/or business logic. Another one is a bridge for the different language.
Double underscore does not have any special meaning, just a convention I often use, trying to follow behaviour of the NS_REFINED_FOR_SWIFT attribute. Also, when showing .swiftinterface, Xcode hides members with names starting from underscore. IIRC, this also excludes it from the autocompletion. So it makes __price kinda hidden in Swift.
But in Objective-C, things are other way around. price is not exported to ObjC at all, because it is not @objc. And __price is exported as NSNumber *price. So both languages use identifier price and get API suitable for the language.
If you need to bridge in the opposite direction - from Objective-C to Swift, then you can declare Objective-C declaration using NS_REFINED_FOR_SWIFT and then implement extension in Swift that provides more Swift-friendly wrappers:
@interface Car: NSObject
// Gets exported to Swift as `var __price: NSNumber?`
@property(nonatomic, readonly, nullable) NSNumber *price NS_REFINED_FOR_SWIFT;
@end
extension Car {
var price: Int? { __price.map(\.intValue) }
}