【问题标题】:completion handler's error in swift 3 and Xcode 8swift 3 和 Xcode 8 中的完成处理程序错误
【发布时间】:2016-09-15 10:32:05
【问题描述】:

我在 Xcode 7.3 中有 swift 2.2 版本的工作项目。现在我已经更新了 Xcode 8 并迁移到了 swift 3。现在我的项目包含错误,特别是对于像 afnetworking 的成功块这样的块。

这给出了错误

Cannot convert value of type '() -> ()' to expected argument type '((URLSessionDataTask, Any?) -> Void)?'

我不明白如何解决这个问题以按照 swift 3 工作。

Facebook 登录也有类似的错误。

这给出了错误

Cannot convert value of type '(FBSDKLoginManagerLoginResult!, NSError!) -> Void' to expected argument type 'FBSDKLoginManagerRequestTokenHandler!'

Cannot convert value of type '(_, _, NSError!) -> Void' to expected argument type 'FBSDKGraphRequestHandler!'

所有错误都与 swift 3 中的处理程序块有关。我不理解错误,因此无法解决。任何帮助将不胜感激。提前致谢。

【问题讨论】:

    标签: ios facebook afnetworking swift3 xcode8


    【解决方案1】:

    对于 facebook - 问题在于关于将 Objective-c 函数参数转换为 Swift 的新 Swift 规则。

    以前,如果objective-c 代码中的参数没有可空性属性(如nonnullnullable),Swift 会将其转换为!,使其成为非可选(强制解包)。现在它使用? 将其转换为可选。这就是你收到错误的原因。在您将其作为登录回调之前:

    (FBSDKLoginManagerLoginResult!, NSError!) -> Void
    

    现在你需要输入:

    (FBSDKLoginManagerLoginResult?, Error?) -> Void
    

    另外,如您所见,现在您将看不到 NSError 类。而不是那个 Swift 会放Error。这也是新规则。现在所有在类名中前缀的 "NS" 都在 Swift 中被删除了(NSObject -> Object; NSError -> Error)。

    Swift 3.0 中 facebook 登录的工作代码示例:

    let manager = FBSDKLoginManager()
    
    manager.logIn(withReadPermissions: ["public_profile"], from: self.controller) {
        (loginResult: FBSDKLoginManagerLoginResult?, error: Error?) in
    
    }
    

    Swift 3.0 中 facebook 请求的工作代码示例:

    let request = FBSDKGraphRequest()
    
    request.start {
         (connection: FBSDKGraphRequestConnection?, result: Any?, error: Error?) in
    
    }
    

    如你所见,现在它使用Any 类型而不是objective-c id。在 Swift 2.2 中,它使用 AnyObject。这也是新的 Swift 转换规则。

    您不需要指定回调参数类型。我在代码中这样做是为了突出它们的真实类型。所以你可以在没有它们的情况下编写代码:

    let manager = FBSDKLoginManager()
    
    manager.logIn(withReadPermissions: ["public_profile"], from: self.controller) { (loginResult, error) in }
    
    
    let request = FBSDKGraphRequest()
    
    request.start { (connection, result, error) in }
    

    但您需要记住它们现在是可选的。

    总结一些可能会影响你回调代码的转换规则:

    1. 如果在 Objective-c 中未指定可空性属性,则闭包参数是可选的
    2. 所有 "NS" 前缀在 Swift 中为 Objective-c 类被移除
    3. 如果 Objective-c 函数有 id 参数,在 Swift 3.0 中它将有类型 Any 而不是 AnyObject

    【讨论】:

    • @Max 查看我正在运行的项目中的代码示例。我还放了回调参数类型的定义以显示它到底是什么,但没有必要。
    • 是的,我和你的一样,然后也有错误。然后我删除了:FBSDKLoginManagerLoginResult?和:错误?然后错误消失了。
    • @Max 尝试清理项目。它应该工作。如果没有,请自行检查它需要什么样的参数。
    • 尝试所有可能并一一解决,语法变化很多。
    • @Max 您是否通过将参数更改为可选参数来解决 Facebook 的问题?
    【解决方案2】:

    虽然在此之前我不知道 Xcode 想要通知我有关错误的错误,但我已经删除了带有对象的类型规范并且它起作用了。

    作为

    manager.post(methodname, parameters: param, progress: nil, success:{ (dataTask, responseObj) in
    
                    if let dict : NSDictionary = responseObj as? NSDictionary {
    
                        print("Response of \(methodname) : \(dict)")
    
                        if dict.object(forKey: "response") as? String == "success" {
                            CompletionHandler(true, dict)
                        } else {
                            CompletionHandler(false, dict)
                        }
    
    
                    }
    
            })
    

    这里关于问题错误在dataTaskresponseObj 给出,它们具有指定的类型。删除类型后,它工作正常。

    与 facebook 登录相同

    @IBAction func fbLoginClicked(_ sender: AnyObject) {
    
            let app = UIApplication.shared.delegate as! AppDelegate
    
            app.fbLoginManager = FBSDKLoginManager()
            app.fbLoginManager.logOut()
            app.fbLoginManager.loginBehavior = FBSDKLoginBehavior.native
    
    
            app.fbLoginManager.logIn(withReadPermissions: ["email"], from: self, handler: { (result, error) -> Void in
                if error != nil {
                    print(error?.localizedDescription)
                } else {
    
                    if (result! as FBSDKLoginManagerLoginResult).isCancelled == true {
    
                    } else {
    
                        self.fetchFacebookUserDetail()
                    }
                }
            })
    
        }
    

    在这里,我还删除了 resulterror 的类型规范并解决了问题。并在整个应用程序中遵循这一点,它起作用了。我可以毫无错误地运行该项目,并且它正在运行。谢谢。

    【讨论】:

    • 您的一半回答对我帮助很大。我希望你能帮我完成另一半。我有一个委托方法接受来自目标 c 的 NSError,但是当我将其转换为 swift 时,我无法弄清楚语法,它抱怨我的类不符合它来自的协议...
    • @LenaBru 因为 NSError 在 swift 3 中变成了错误,所以相应地改变你的方法。
    • 要获取 userInfo 成员,我必须将其转换为“as!NSError”......这太可怕了......
    • @LenaBru。我也遇到过。我还需要来自 NSError 的 userInfo,因为我从服务器收到了带有错误代码 400 和 json 的 json 响应,但我现在无法通过这种方法获取这些信息。所以我现在把 afnetworking 改成了 alamofire。
    • @Felix 只需将 dataTask 对象替换为 _(下划线)
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2017-10-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-02-24
    • 2017-02-08
    • 1970-01-01
    相关资源
    最近更新 更多