无法使用带有完成处理程序的函数进行抛出
Can't get throws to work with function with completion handler
我正在尝试使用完成处理程序将 throws
添加到我现有的函数中,但我不断收到一条警告说 no calls throwing functions occur within try expression
。在我抛出错误的部分,我收到一条错误消息
invalid conversion from throwing function of type '() throwing -> Void' to non-throwing function type.
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()
}
请谨慎阅读以下内容。我还没有使用 Swift 2.0:
您创建了一个 "dataTask" task
的完成处理程序,其中有一个 throw,但您的 login3 方法中唯一的实际代码是 task.resume()
。直到 login3
returns 之后才会执行完成处理程序。 (实际上,它是另一个对象的参数,因此编译器不知道该代码会发生什么。)
据我了解,您的 login3
方法的实际自上而下主体必须包含一个抛出。由于它是一种异步方法,因此您不能这样做。因此,不要让 login3
函数抛出异常。而是让它将错误对象传递给它的完成处理程序。
在我看来,这是由您的函数签名引起的。在 @IBAction func loginPressed(sender: AnyObject)
中,您不必在调用 login3
时使用 try,因为函数本身未标记为抛出,但完成处理程序是。但实际上 login3
的完成闭包永远不会抛出,因为你在 do {} catch {}
块中执行所有抛出函数,所以你可以尝试从 login3
中删除 throws
注释完成闭包,如果您在 login3
中发现错误并得到相应的结果,也会调用闭包。通过这种方式,您可以在 do {} catch {}
块中处理 login3
内的所有抛出函数,并使用合适的值调用完成处理程序。
通常我也不知道您可以像在@IBAction 中那样在没有前面的 do {}
块的情况下进行捕获。
你问的是 X,我回答的是 Y,但以防万一...
总是有可能将抛出功能添加到您的函数而不是完成处理程序:
func login3(params:[String: String], completion: (result:Bool) -> Void) throws {
...
}
然后你可以在 IBAction 中调用它:
do {
try self.login3(dict) { result -> Void in
...
}
} catch {
print(error)
}
你可以做的是将错误封装到一个可抛出的闭包中,就像下面的代码一样,以实现你想要的:
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}
我强烈推荐你一篇关于在异步调用中使用 try/catch
的优秀文章 Using try / catch in Swift with asynchronous closures
希望对你有所帮助。
我正在尝试使用完成处理程序将 throws
添加到我现有的函数中,但我不断收到一条警告说 no calls throwing functions occur within try expression
。在我抛出错误的部分,我收到一条错误消息
invalid conversion from throwing function of type '() throwing -> Void' to non-throwing function type.
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()
}
请谨慎阅读以下内容。我还没有使用 Swift 2.0:
您创建了一个 "dataTask" task
的完成处理程序,其中有一个 throw,但您的 login3 方法中唯一的实际代码是 task.resume()
。直到 login3
returns 之后才会执行完成处理程序。 (实际上,它是另一个对象的参数,因此编译器不知道该代码会发生什么。)
据我了解,您的 login3
方法的实际自上而下主体必须包含一个抛出。由于它是一种异步方法,因此您不能这样做。因此,不要让 login3
函数抛出异常。而是让它将错误对象传递给它的完成处理程序。
在我看来,这是由您的函数签名引起的。在 @IBAction func loginPressed(sender: AnyObject)
中,您不必在调用 login3
时使用 try,因为函数本身未标记为抛出,但完成处理程序是。但实际上 login3
的完成闭包永远不会抛出,因为你在 do {} catch {}
块中执行所有抛出函数,所以你可以尝试从 login3
中删除 throws
注释完成闭包,如果您在 login3
中发现错误并得到相应的结果,也会调用闭包。通过这种方式,您可以在 do {} catch {}
块中处理 login3
内的所有抛出函数,并使用合适的值调用完成处理程序。
通常我也不知道您可以像在@IBAction 中那样在没有前面的 do {}
块的情况下进行捕获。
你问的是 X,我回答的是 Y,但以防万一...
总是有可能将抛出功能添加到您的函数而不是完成处理程序:
func login3(params:[String: String], completion: (result:Bool) -> Void) throws {
...
}
然后你可以在 IBAction 中调用它:
do {
try self.login3(dict) { result -> Void in
...
}
} catch {
print(error)
}
你可以做的是将错误封装到一个可抛出的闭包中,就像下面的代码一样,以实现你想要的:
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}
我强烈推荐你一篇关于在异步调用中使用 try/catch
的优秀文章 Using try / catch in Swift with asynchronous closures
希望对你有所帮助。