使用Swift语法处理块中的错误

时间:2015-08-19 12:09:34

标签: ios swift

此处的错误处理感觉不对。有人建议如何改进吗?使用可选绑定来建立错误和返回值变量。

那很酷?

class ChargePointsFetcher {

func getDevices(location: NSURL, completion handler:([ChargeDevice]?, error: NSError?) -> Void) {

    let request = NSURLRequest(URL: location)
    let session = NSURLSession.sharedSession()
    let task = session.dataTaskWithRequest(request, completionHandler: { (let data, let response, let error) -> Void in

        var returnValue: NSError?

        if let e = error {
            returnValue = e
        }

        var collection: [ChargeDevice]?

        if returnValue == nil {

            collection = [ChargeDevice]()
            var parsingError: NSError?

            if let json: NSDictionary = NSJSONSerialization.JSONObjectWithData(data, options: .AllowFragments, error: &parsingError) as? NSDictionary {
                if let chargeDevices = json.valueForKey("ChargeDevice") as? NSArray {
                    for chargeDevice in chargeDevices {
                        let device = ChargeDevice()
                        collection!.append(device)
                    }
                }
            }

            if let e = parsingError {
                returnValue = e
            }

        }

        dispatch_async(dispatch_get_main_queue(), { () -> Void in
            handler(collection, error: returnValue)
        })
    })

}

}

1 个答案:

答案 0 :(得分:1)

在我看来,你应该尽可能地避免使用(Value?, Error?)模式。由于两种组合是非法的,因此会产生坏的角落情况相反,如果可能的话,我建议(Value, Error?)任何时候Value都有明智的“零”。在这种情况下,“零”是“空阵列”。这非常接近地匹配ObjC意义,因为nil NSArray非常类似于空数组。

这样做,您可以大大简化此代码:

func getDevices(location: NSURL, completion handler:([ChargeDevice], error: NSError?) -> Void) {

    // Note that error is marked "var" so we can modify it, and switched from NSError! to NSError?
    let task = session.dataTaskWithRequest(request, completionHandler: { (let data, let response, var error: NSError?) -> Void in
        var result = [ChargeDevice]()

        if error == nil {
            // Avoid NSArray and NSDictionary wherever you can in Swift
            if let
                json = NSJSONSerialization.JSONObjectWithData(data,
                    options: .AllowFragments,
                    error: &error
                    ) as? [String:AnyObject],

                chargeDevices = json["ChargeDevice"] as? [AnyObject] {
                    // map is much simpler in this case, but in your full code, for may fine fine
                    result = chargeDevices.map{ _ in ChargeDevice() }
            }
        }

        dispatch_async(dispatch_get_main_queue(), { () -> Void in
            handler(result, error: error)
        })
    })
}

请注意,在您的代码和我的代码中,不正确但有效的JSON不会产生任何类型的错误。它会悄悄跳过as?次来电。我可能会将所有这些JSON工作移动到另一个函数中,以防止这个闭包失控。

此处的另一种方法称为Result。我的首选示例是Rob Rix's。虽然我已经在Result做了很多工作,但我个人觉得很难干净地与Cocoa联系起来。如果您的整个程序使用它,并且如果您封装了大多数Cocoa交互,那么它很有用,但我发现使用它作为一次性解决方案很麻烦。 (很多人在这里不同意我,这只是我的经验。Result绝对值得探索以形成自己的观点。)