Ari K
Ari K

Reputation: 434

Why are my IBOutlet-connected vars not instantiated when I create an instance?

I set some global variables equal to parameters of a class after it's instantiation. The class is defined as so:

import Foundation
import UIKit

class LogIn : UIViewController{

    var test:Int = 1

    @IBOutlet var login_icon: UIImageView!

    @IBOutlet var username_field: UITextField!
    @IBOutlet var password_field: UITextField!
    @IBOutlet var login_button: UIButton!
    @IBOutlet var createaccount_button: UIButton! 

}

The global variables are instantiated as so (within a viewDidAppear method):

func showLoginView(){
    self.startup_animation.image = self.seq_6
    let login_view = LogIn()
    self.login_icon = login_view.login_icon.image //Doesnt work
    self.username_field = login_view.username_field //Doesnt work
    self.password_field = login_view.password_field //Doesnt work
    self.login_button = login_view.login_button //Doesnt work
    self.createaccount_button = login_view.createaccount_button  //Doesnt work
    self.int_testval = login_view.test //Works  
}

All IBOutlets-connected variables after instantiation are nil values, but var test is instantiated fine. Why is this?

Thanks!

Additional Context The showLoginView function is called with the viewDidAppear function. The whole class looks like so:

class StartupViewController: UIViewController {

var images: [UIImage]!

var animatedImage: UIImage!

@IBOutlet var startup_animation: UIImageView!
@IBOutlet var startup_text: UIImageView!

var login_icon: UIImage!
var username_field: UITextField!
var password_field: UITextField!
var login_button: UIButton!
var createaccount_button: UIButton!


var seq_1 : UIImage!
var seq_2 : UIImage!
var seq_3 : UIImage!
var seq_4 : UIImage!
var seq_5 : UIImage!
var seq_6 : UIImage!
var seq_7 : UIImage!
var seq_8 : UIImage!

var rec_1 : UIImage!
var rec_2 : UIImage!
var rec_3 : UIImage!
var rec_4 : UIImage!
var rec_5 : UIImage!
var rec_6 : UIImage!

override func viewDidLoad() {
    super.viewDidLoad()

}

override func viewDidAppear(_ animated: Bool) {

    super.viewDidAppear(animated)

    seq_1 = UIImage(named: "Eceipt_seq1")
    seq_2 = UIImage(named: "Eceipt_seq2")
    seq_3 = UIImage(named: "Eceipt_seq3")
    seq_4 = UIImage(named: "Eceipt_seq4")
    seq_5 = UIImage(named: "Eceipt_seq5")
    seq_6 = UIImage(named: "Eceipt_seq6")
    seq_7 = UIImage(named: "Eceipt_seq7")
    seq_8 = UIImage(named: "Eceipt_seq8")

    images = [seq_1 ,seq_2, seq_3, seq_4, seq_5, seq_6, seq_7, seq_8]

    animatedImage = UIImage.animatedImage(with: images, duration: 0.8)

    startup_animation.image = animatedImage

    let transition_text = UIImage(named: "Eceipt_logo")

    UIView.transition(with: self.startup_text, duration: 3.0, options: .transitionCrossDissolve,
                      animations: {
                        self.startup_text.image = transition_text
    },
                      completion: { (finished: Bool) -> () in
                        self.showLoginView()
    })

}

func showLoginView(){
    self.startup_animation.image = self.seq_6
    let login_view = LogIn()
    self.login_icon = login_view.login_icon.image
    self.username_field = login_view.username_field
    self.password_field = login_view.password_field
    self.login_button = login_view.login_button
    self.createaccount_button = login_view.createaccount_button
}

Upvotes: 0

Views: 376

Answers (2)

Rico Crescenzio
Rico Crescenzio

Reputation: 4226

I think the problem is that you're instantiating the LogIn view controller by doing let login_view = LogIn(). When you instantiate a view controller with its empty initializer, every IBOutlet will be nil because the view controller is not "taken" from a storyboard (or a xib). If you want to use iboutles you must instantiate the view controller from a storyboard or from a xib; in your case (with the storyboard), you should instantiate it by doing:

let storyboard = UIStoryboard(name: "Main", bundle: nil) // name is the filename of the storyboard that contains the vc
let vc = storyboard.instantiateViewController(withIdentifier: "LogIn") as! LogIn // you can cast to have the exact view controller type
present(vc, animated: true, completion: nil)

Make sure that the view controller in your storyboard has the identifier "LogIn".

Upvotes: 1

Sweeper
Sweeper

Reputation: 271410

I think you are misunderstanding the use of @IBOutlet.

@IBOutlet just means that it is an outlet of a view or some other object in the xib or storyboard file.

Your views are nil not because they are outlets, but because they are implicitly unwrapped optionals, which is nil if you don't give it a value.

test is not nil, because 1) it is not an optional type and 2) it has a value of 1.

I suggest you put the @IBOutlets in a UIViewController or UIView subclass and connect the appropriate views from the storyboard/xib file to it. This way, they will be initialised by the time the viewDidLoad method or awakeFromNib method is called.

EDIT:

It seems like that you already control+dragged the views to the LogIn class. In that case, check if the circles to the left of the outlets are filled. If they are, that means they are properly connected. You just need to wait until awakeFromNib gets called. If they are not, try connecting them again. Alternatively, just connect all your outlets directly to the view controller, which saves you lots of trouble.

EDIT 2:

Now that I understand what you are trying to do, here is what you should do. You just seems to want to present the LogIn VC. So instead of assigning every view to self, properly present it with the present method.

let vc = UIStoryboard.main!.instantiateViewController(withIdentifier: "Login")
present(vc, animated: true, completion: nil)

Remember to give your login VC in the storyboard a Storyboard ID of "Login".

Upvotes: 1

Related Questions