Calling NSException.raise() in Swift

后端 未结 3 1581
遥遥无期
遥遥无期 2021-02-20 06:26

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         


        
相关标签:
3条回答
  • 2021-02-20 07:03

    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<AnyObject>) 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<AnyObject>.passUnretained(obj!).toOpaque() :
        (nil as COpaquePointer)
    }
    
    0 讨论(0)
  • 2021-02-20 07:09

    The problem seems to have been that I didn't treat the error as an optional. The following works:

    var error: NSError?
    NSException.raise("Exception", format:"Error: %@", arguments:getVaList([error!]))
    

    Or you could do the following in case error is nil:

    NSException.raise("Exception", format:"Error: %@", arguments:getVaList([error ?? "nil"]))
    
    0 讨论(0)
  • 2021-02-20 07:22
    var e = NSException(name:"name", reason:"reason", userInfo:["key":"value"])
    e.raise()
    

    Or:

    var e = NSException(name:"name", reason:"reason", userInfo:nil)
    e.raise()
    

    Or:

    NSException(name:"name", reason:"reason", userInfo:nil).raise()
    
    0 讨论(0)
提交回复
热议问题