swift2 无法让掷回与具有完成行程常式的函式搭配使用

5kgi1eie  于 2022-11-06  发布在  Swift
关注(0)|答案(4)|浏览(145)

我试图用一个完成处理程序向现有函数添加一个throws,但是我一直收到一个no calls throwing functions occur within try expression的警告。

从类型为'()throwing -〉Void'的引发函数到非引发函数类型的转换无效。

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()

}
bxpogfeg

bxpogfeg1#

您可以做的是将错误封装到一个可抛出的闭包中,如以下代码所示,以实现所需的效果:

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的优秀文章。
我希望这对你有帮助。

mzaanser

mzaanser2#

你问X我回答Y,但以防万一...
总是有可能将抛出功能添加到函数中,而不是添加到完成处理程序中:

func login3(params:[String: String], completion: (result:Bool) -> Void) throws {
    ...
}

然后,您可以从IBAction内部调用它:

do {
    try self.login3(dict) { result -> Void in
        ...
    }
} catch {
    print(error)
}
deikduxw

deikduxw3#

我对Swift 2.0还没有做过太多的工作,请你带着一点怀疑阅读下面的内容:
您创建了一个“dataTask”task,它的完成处理程序中有一个throw,但login3方法中唯一的实际代码是task.resume()。完成处理程序在login3返回之前不会执行。(实际上,它是另一个对象的参数,因此编译器不知道该代码会发生什么。)
据我所知,你的login3方法的自上而下的主体必须包含一个throw。因为它是一个异步方法,你不能这样做。因此,不要让你的login3函数throw。相反,让它传递一个error对象给它的完成处理程序。

oiopk7p5

oiopk7p54#

在我的印象中,这是由函数的签名引起的。在@IBAction func loginPressed(sender: AnyObject)中,当调用login3时,你不必使用try,因为函数本身没有被标记为throw,而是完成处理程序被标记为throw。但事实上,login3的完成闭包永远不会throw,因为你在do {} catch {}块中执行所有的throw函数。因此,您可以尝试从login3完成闭包中删除throws注解,如果您在login3中捕获到错误并得到相应的结果,也可以调用闭包。这样,您可以在do {} catch {}块中处理login3内部的所有抛出函数,并使用合适的值调用完成处理程序。
通常,我也不知道您是否可以像在@IBAction中那样在没有前面的do {}块的情况下进行捕获。

相关问题