我尝试使用完成处理程序向现有函数添加throws
,但我不断收到no calls throwing functions occur within try expression
的警告。在我抛出错误的部分,我收到错误说
投掷函数类型'()投掷无效转换 - >虚空'非投掷功能类型。
enum LoginError: ErrorType {
case Invalid_Credentials
case Unable_To_Access_Login
case User_Not_Found
}
@IBAction func loginPressed(sender: AnyObject) {
do{
try self.login3(dict, completion: { (result) -> Void in
if (result == true)
{
self.performSegueWithIdentifier("loginSegue", sender: nil)
}
})
}
catch LoginError.User_Not_Found
{
//deal with it
}
catch LoginError.Unable_To_Access_Login
{
//deal with it
}
catch LoginError.Invalid_Credentials
{
//deal with it
}
catch
{
print("i dunno")
}
}
func login3(params:[String: String], completion: (result:Bool) throws -> Void)
{
//Request set up
let task = session.dataTaskWithRequest(request, completionHandler: {data, response, error -> Void in
do {
let json = try NSJSONSerialization.JSONObjectWithData(data, options: .MutableLeaves) as? NSDictionary
if let parseJSON = json
{
let userID = parseJSON["user_id"] as? Int
let loginError = parseJSON["user_not_found"] as? String
let validationError = parseJSON["invalid_credentials"] as? String
let exception = parseJSON["unable_to_access_login"] as? String
var responseArray = [(parseJSON["user_id"] as? Int)]
if userID != nil
{
dispatch_async(dispatch_get_main_queue()) {
completion(result:true)
}
}
else if loginError != ""
{
dispatch_async(dispatch_get_main_queue()){
completion(result: false)
self.loginErrorLabel.text = loginError
throw LoginError.User_Not_Found
}
}
else if validationError != ""
{
dispatch_async(dispatch_get_main_queue()){
completion(result:false)
self.validationErrorLabel.text = validationError
throw LoginError.Invalid_Credentials
}
}
else if exception != nil
{
dispatch_async(dispatch_get_main_queue()){
completion(result:false)
self.exceptionErrorLabel.text = "Unable to login"
throw LoginError.Unable_To_Access_Login
}
}
}
else
{
}
}
catch let parseError {
// Log the error thrown by `JSONObjectWithData`
})
task.resume()
}
答案 0 :(得分:12)
你可以做的是将错误封装到一个throwable闭包中,就像在下面的代码中一样,以实现你想要的:
func login3(params:[String: String], completion: (inner: () throws -> Bool) -> ()) {
let task = session.dataTaskWithRequest(request, completionHandler: { data, response, error -> Void in
let json = try NSJSONSerialization.JSONObjectWithData(data, options: .MutableLeaves) as? NSDictionary
if let parseJSON = json {
let userID = parseJSON["user_id"] as? Int
let loginError = parseJSON["user_not_found"] as? String
let validationError = parseJSON["invalid_credentials"] as? String
let exception = parseJSON["unable_to_access_login"] as? String
var responseArray = [(parseJSON["user_id"] as? Int)]
if userID != nil {
dispatch_async(dispatch_get_main_queue()) {
completion(inner: { return true })
}
}
else if loginError != ""
{
dispatch_async(dispatch_get_main_queue()) {
self.loginErrorLabel.text = loginError
completion(inner: { throw LoginError.User_Not_Found })
}
}
else if validationError != ""
{
dispatch_async(dispatch_get_main_queue()) {
self.validationErrorLabel.text = validationError
completion(inner: {throw LoginError.Invalid_Credentials})
}
}
else if exception != nil
{
dispatch_async(dispatch_get_main_queue()){
self.exceptionErrorLabel.text = "Unable to login"
completion(inner: {throw LoginError.Unable_To_Access_Login})
}
}
}
else
{
}
}
task.resume()
}
您可以通过以下方式调用它:
self.login3(dict) { (inner: () throws -> Bool) -> Void in
do {
let result = try inner()
self.performSegueWithIdentifier("loginSegue", sender: nil)
} catch let error {
print(error)
}
}
诀窍是login3
函数采用类型为'inner'
的名为() throws -> Bool
的附加闭包。这个闭包将提供计算结果,或者它将抛出。闭包本身是在计算过程中通过以下两种方法之一构建的:
inner: {throw error}
inner: {return result}
我强烈建议您撰写一篇关于在异步调用Using try / catch in Swift with asynchronous closures中使用try/catch
的优秀文章
我希望这对你有所帮助。
答案 1 :(得分:0)
用一粒盐阅读下面的内容。我还没有使用过Swift 2.0:
您创建了一个“dataTask”task
,其中的完成处理程序有一个抛出,但您的login3方法中唯一的实际代码是task.resume()
。在login3
返回之后,完成处理程序才会执行。 (实际上,它是另一个对象的参数,因此编译器不知道该代码会发生什么。)
据我了解,login3
方法的实际顶部到底部的主体必须包含一个抛出。因为它是一种异步方法,所以你不能这样做。因此,不要让你的login3
函数抛出。而是让它将错误对象传递给它的完成处理程序。
答案 2 :(得分:0)
在我的印象中,这是由你的功能签名引起的。在@IBAction func loginPressed(sender: AnyObject)
中,您在调用login3
时不必使用try,因为函数本身未标记为throw,但完成处理程序是。但实际上login3
的完成关闭将永远不会在do {} catch {}
块中执行所有抛出函数时抛出,因此您可以尝试从throws
中删除login3
注释完成闭包,如果你在login3
中发现错误并且有相应的结果,也会调用闭包。这样,您可以在login3
块中处理do {} catch {}
内的所有抛出函数,并使用合适的值调用完成处理程序。
一般来说,我也不知道你可以像在@IBAction中那样在没有前面的do {}
块的情况下捕获。
答案 3 :(得分:0)
你要求X而我正在回答Y,但以防万一...
总是有可能将抛出功能添加到您的函数而不是完成处理程序:
func login3(params:[String: String], completion: (result:Bool) -> Void) throws {
...
}
然后你可以从IBAction里面调用它:
do {
try self.login3(dict) { result -> Void in
...
}
} catch {
print(error)
}