I\'m trying to raise an exception in Swift by calling NSException.raise(). The definition is:
class func raise(_ name: String!, format format: String!, arguments
As the questioner discovered, the issue is that an optional object does not conform to CVarArgType
, and a non-optional object does, so you need to do some kind of unwrapping.
If we look at the types that conform to CVarArgType
, they include primitive numeric types, COpaquePointer
, and NSObject
has an extension that makes NSObject
conform to it. Unfortunately, that's a direct NSObject
, not NSObject?
, and not AnyObject?
as we might want. So if you have an NSObject?
, you could unwrap it with !
, but then if it's nil
, it'll crash. Or if you have an object that is not a subtype of NSObject
, then you also cannot use this.
But in C/Objective-C, you could pass any pointer type as a vararg, including any object pointer, and it worked no matter if it was a null pointer or not. How do we replicate this behavior in Swift?
By the way, they couldn't make AnyObject?
(i.e. Optional
) conform to CVarArgType
, because you cannot define a method (whether in the class directly, or an extension) for a specific type argument of a generic type (like "template specialization" in C++). Perhaps Apple will add it in the future. But right now a method of Optional
must work for all type arguments. But we don't want to be able to pass non-object optionals as var args, so that doesn't work.
However, we can make a function that converts optional objects to CVarArgType
. We can take advantage of NSObject
's conformance, and handle the case it doesn't handle -- nil
. nil
is just a null pointer, and we can instead pass a different kind of null pointer, a COpaquePointer
null pointer, and it will work since all null pointers are the same at runtime:
import Foundation
func nsObjectToVarArg(obj: NSObject?) -> CVarArgType {
return obj ?? (nil as COpaquePointer)
}
What about for objects that are not (or we don't know are) subtypes of NSObject
? I made a version that is however more sketchy:
func anyObjectToVarArg(obj: AnyObject?) -> CVarArgType {
return (obj != nil) ?
Unmanaged.passUnretained(obj!).toOpaque() :
(nil as COpaquePointer)
}