Hareesh Jayanthi
Hareesh Jayanthi

Reputation: 39

Using Struct to pass a variable Swift

I'm trying to use a Struct to pass some variables that I get from a Facebook Graph Request such as email, name, gender, etc. I've created the Struct ('fbDemographics') and the variables in 'ViewController' but I get an error when I try to call the struct and one of the variables in 'SecondViewController' (Type 'ViewController' has no member 'fbDemographics'). I've never used struct before so a bit baffled why I am getting this error. Thanks for any thoughts. The code for both view controllers is below:

class ViewController: UIViewController, FBSDKLoginButtonDelegate {

override func viewDidLoad() {
    super.viewDidLoad()

    struct fbDemographics {

        static var relationship_status: String?
        static var gender: String?
        static var user_education_history: String?
        static var user_location: String?
        static var email: String?
        static var name: String?

    }     

    FBSDKGraphRequest(graphPath: "me", parameters: ["fields": "id, name, relationship_status, gender, user_location, user_education_history, email"]).start(completionHandler: { (connection, result, error) -> Void in
        if (error == nil){
            //let fbDetails = result as! NSDictionary
            //print(fbDetails)

            if let userDataDict = result as? NSDictionary {
                fbDemographics.gender = userDataDict["gender"] as? String
                fbDemographics.email = userDataDict["email"] as? String
                fbDemographics.name = userDataDict["name"] as? String
                fbDemographics.user_location = userDataDict["user_location"] as? String
                fbDemographics.user_education_history = userDataDict["user_education_history"] as? String
                fbDemographics.relationship_status = userDataDict["relationship_status"] as? String


                let myEducation = fbDemographics.user_education_history
                let myEmail = fbDemographics.email
                let myGender = fbDemographics.gender
                let myName = fbDemographics.name
                let myStatus = fbDemographics.relationship_status
                let myLocation = fbDemographics.user_location                   

                self.performSegue(withIdentifier: "LoginToHome", sender: (Any).self)


            }


        }

SECOND VIEW CONTROLLER

class SecondViewController: UIViewController {

@IBAction func verticalSliderChanged(_ sender: UISlider) {

        let currentValue = String(sender.value);

        sliderLabel.text = "\(currentValue)"

    func viewDidLoad() {
        super.viewDidLoad()

        ***ViewController.fbDemographics.myEmail***

    }
}

Upvotes: 1

Views: 3967

Answers (1)

Rob
Rob

Reputation: 437382

The problem is that you've defined your struct inside viewDidLoad. So the scope is limited to that method. Move it out of viewDidLoad, but still in ViewController, and you should be able to access it from the SecondViewController. Obviously, you'll have to fix that reference to myEmail, too, because it's called email. Also, in your SecondViewController you should pull viewDidLoad implementation out of the verticalSliderChanged method; the viewDidLoad should be a top-level instance method of SecondViewController, not defined inside another method.

There are deeper problems here, though. Rather than using struct with static variables, you really should make those simple instance variables, create an instance of your FbDemographics type (note, start struct types with uppercase letter), and then pass this instance in prepare(for:sender:).


For example, the right way to pass data would be to:

  • eliminate static variables;
  • give your struct a name that starts with uppercase letter;
  • create instance of your struct; and
  • pass this instance to the destination view controller in prepare(for:sender:).

E.g.

struct FbDemographics {
    var relationshipStatus: String?
    var gender: String?
    var userEducationHistory: String?
    var userLocation: String?
    var email: String?
    var name: String?
}

class ViewController: UIViewController {

    var demographics: FbDemographics?

    override func viewDidLoad() {
        super.viewDidLoad()

        performRequest()   // I actually don't think you should be initiating this in `viewDidLoad` ... perhaps in `viewDidAppear`
    }

    override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
        if let destination = segue.destination as? SecondViewController {
            destination.demographics = demographics
        }
    }

    func performRequest() {
        FBSDKGraphRequest(graphPath: "me", parameters: ["fields": "id, name, relationship_status, gender, user_location, user_education_history, email"]).start { connection, result, error in
            guard let userDataDict = result as? NSDictionary, error == nil else {
                print("\(error)")
                return
            }

            self.demographics = FbDemographics(
                relationshipStatus: userDataDict["relationship_status"] as? String,
                gender: userDataDict["gender"] as? String,
                userEducationHistory: userDataDict["user_education_history"] as? String,
                userLocation: userDataDict["user_location"] as? String,
                email: userDataDict["email"] as? String,
                name: userDataDict["name"] as? String
            )

            self.performSegue(withIdentifier: "LoginToHome", sender: self)
        }
    }

}

And then SecondViewController could:

class SecondViewController: UIViewController {

    var demographics: FbDemographics!

    override func viewDidLoad() {
        super.viewDidLoad()

        let value = demographics.email  // this should work fine here
    }

}

Upvotes: 3

Related Questions