天天看點

Swift 與 Objc Exception

一、背景

  Swift具備完善的Error handle機制,對于純Swift下面的Error,在編碼的時候能夠正确處理。

  在使用try? 處理抛出Error的方法的時候,會忽略Error,直接傳回nil

二、Swift 與 Objc下面的Exception

  下面的代碼是經常遇到的一種場景,Swift序列化

private func serialize(message: Message, pretty: Bool) -> String? {
        var result: String?
        do {
            let data = try JSONSerialization.data(withJSONObject: message, options: pretty ? .prettyPrinted : JSONSerialization.WritingOptions(rawValue: 0))
            result = String(data: data, encoding: .utf8)
        } catch let error {
            log(error)
        }
        return result
    }
           

  雖然這個序列化的API有标注throws标記,但是抛出的異常是objc的異常,這個swift中的try catch是catch不住的

/* Generate JSON data from a Foundation object.
   If the object will not produce valid JSON then an exception will be thrown. 
  Setting the NSJSONWritingPrettyPrinted option will generate JSON with whitespace designed to make the output more readable. 
  If that option is not set, the most compact possible JSON will be generated. 
  If an error occurs, the error parameter will be set and the return value will be nil. 

  The resulting data is a encoded in UTF-8.
     */
    open class func data(withJSONObject obj: Any, options opt: JSONSerialization.WritingOptions = []) throws -> Data
           

  如果傳遞一個非可序列化的對象,那麼将會導緻下面的Crash

Swift 與 Objc Exception

  三、規避方案

  Swift部分的方法存在throws的時候,需要特别注意是不是抛出的objc異常,如果是,那麼需要特别處理,針對本例子當中,可以采用下面的方法判斷一個對象是否可以序列化

/* Returns YES if the given object can be converted to JSON data, NO otherwise. The object must have the following properties:
        - Top level object is an NSArray or NSDictionary
        - All objects are NSString, NSNumber, NSArray, NSDictionary, or NSNull
        - All dictionary keys are NSStrings
        - NSNumbers are not NaN or infinity
     Other rules may apply. Calling this method or attempting a conversion are the definitive ways to tell if a given object can be converted to JSON data.
     */
    open class func isValidJSONObject(_ obj: Any) -> Bool
           

  修改之後的代碼

guard JSONSerialization.isValidJSONObject(message) else {
            log("\(message) json object not valid")
            return nil
        }
           

  除此之外,stackoverflow上面還提供一種方案,OC下面封裝一個方法,這個方法内部catch所有NSException的異常資訊,然後作為結果傳回出來

  比如:https://stackoverflow.com/questions/32758811/catching-nsexception-in-swift

NSError *tryCatch(void(^tryBlock)(), NSError *(^convertNSException)(NSException *))
{
    NSError *error = nil;
    @try {
        tryBlock();
    }
    @catch (NSException *exception) {
        error = convertNSException(exception);
    }
    @finally {
        return error;
    }
}