2

I recently switched over to Swift 3 from Swift 2 and receiving an error with my signInWithLogin. I am a beginner and tried reading up on this, but it seems like nothing really has changed with this line of code so I'm not sure why I am getting an error and how to resolve. The error seems to appear where the -> in is. Is this something new?

import UIKit

class LoginViewController: UIViewController, UITextFieldDelegate {

    let invalidNetwork = "Oh Snap! You Don't Have Internet!"

    @IBOutlet var usernameField: UITextField!
    @IBOutlet var passwordField: UITextField!
    @IBOutlet var loginButton: UIButton!
    @IBOutlet var errorLabel: UILabel!
    @IBOutlet var imageView: UIImageView!

    var activityIndicator: UIActivityIndicatorView = UIActivityIndicatorView()

    func displayAlert(title: String, message: String) {

        let alert = UIAlertController(title: title, message: message, preferredStyle: UIAlertControllerStyle.alert)
        alert.addAction(UIAlertAction(title: "OK", style: .default, handler: { (action) in
            self.dismiss(animated: true, completion: nil)
        }))
        self.present(alert, animated: true, completion: nil)

    }

    override func viewDidLoad() {
        tapOutKeyboard()

        let spacerView = UIView(frame:CGRect(x:0, y:0, width:20, height:10))
        usernameField.leftViewMode = UITextFieldViewMode.always
        usernameField.leftView = spacerView

        let anotherSpacerView = UIView(frame:CGRect(x:0, y:0, width:20, height:10))
        passwordField.leftViewMode = UITextFieldViewMode.always
        passwordField.leftView = anotherSpacerView

        usernameField.delegate = self
        passwordField.delegate = self
    }

    @IBAction func signupButton(_ sender: Any) {
        _ = self.storyboard?.instantiateViewController(withIdentifier: "SignupViewController")
        UIApplication.shared.openURL(URL(string: url.URL)!)
    }
    struct url {
        static let URL = "https://www.udacity.com/account/auth#!/signup"
    }

    @IBAction func loginButton(_ sender: Any) {
        dismissKeyboard()
        self.view.endEditing(true)

        if usernameField.text == "" || passwordField.text == "" {

            displayAlert(title: "Oh Snap!", message: "Something Went Wrong! Try Again!")

        } else {

            activityIndicator = UIActivityIndicatorView(frame: CGRect(x: 0, y: 0, width: 50, height: 50))
            activityIndicator.center = self.view.center
            activityIndicator.hidesWhenStopped = true
            activityIndicator.activityIndicatorViewStyle = UIActivityIndicatorViewStyle.gray
            view.addSubview(activityIndicator)
            activityIndicator.startAnimating()
            UIApplication.shared.beginIgnoringInteractionEvents()

        }
        let spinner = showSpinner()
        UdacityAPI.signInWithLogin(usernameField.text!, password: passwordField.text!) { (user, error) -> in
            spinner.hide()
            if user != nil {

                //Logged In!

                self.performSegue(withIdentifier: "login", sender: self)

                //Present The Map And Tabbed View
                if let tabBarVC = self.storyboard?.instantiateViewController(withIdentifier: "TabBarViewController") {
                    self.present(tabBarVC, animated: true, completion: nil)

                }

            } else {

                self.displayAlert(title: "Failed Logging In!", message: errorMessage)

            }
            if let response = user as? HTTPURLResponse {
                if response.statusCode < 200 || response.statusCode > 300 {
                    self.displayAlert(title: "Try Again Later!", message: "Error!")
                    return
                }
            }
            if let error = error {
                //Network Error
                if error.code == NSURLErrorNotConnectedToInternet {

                    let alertViewMessage = self.invalidNetwork
                    let okActionAlertTitle = "OK"

                    self.presentAlert("Not Online!", message: alertViewMessage, actionTitle: okActionAlertTitle, actionHandler: nil)

                }
            }
        }
    }
}
Jacob King
  • 6,025
  • 4
  • 27
  • 45

2 Answers2

1

Yep, you're missing the return type after the ->. Looking at your code I would wager that this should be Void but I cannot say for sure as I don't have the docs for your API.

Try adding Void in like so:

UdacityAPI.signInWithLogin(usernameField.text!, password: passwordField.text!) { (user, error) -> Void in
Jacob King
  • 6,025
  • 4
  • 27
  • 45
  • Thank you. I've tried this and I'm still getting a different error that it cannot convert value of type to expected argument type request completion handler. I wasn't sure if I should add my networking code, but here is my repo if that helps understand the issue better: https://github.com/deborahelizabethpadilla/On-The-Map –  Feb 15 '17 at 16:10
  • Okay, another thing you could try is typing out the method call again above, press tab until the block argument is selected and then press enter. Xcode **should** automatically create the block with the correct syntax. Then you can just copy the code from your existing one into the new, correct one. – Jacob King Feb 15 '17 at 16:15
  • I tried this (it's still the same block of syntax) and inserted (user, response, error), but I'm now receiving an error in my displayAlert right below it telling me 'errorMessage' is an unresolved identifier and a warning in my failed network code. I'm a bit confused by this, like I said, I'm a beginner. Is this okay? How is the best way of going about to fix this? –  Feb 15 '17 at 16:32
0

In Swift 3, closures are now assumed to be non-escaping, and you need to mark closures that are escaping with the @escaping attribute. This will invoke the completion handler after the function returns.

Rather than using typealias to define your completion handler, you can alternatively define UdacityAPI's signInWithLogin(:) function as an escaping completion function like so:

static func signInWithLogin(_ username: String, password: String, completion: @escaping (_ data: Data?, _ response: URLResponse?, _ error: NSError?) -> Void) {...}

Then, try calling the function with this syntax:

UdacityAPI.signInWithLogin(usernameField.text!, password: passwordField.text!, completion: { (user, response, error) in
    // your code here
}) 

Side note: see this post for more detailed info on how to use escaping completion functions: Swift 3 :Closure use of non-escaping parameter may allow it to escape

Community
  • 1
  • 1
Mark Barrasso
  • 649
  • 9
  • 17