5

I've got problem with init my parameters in UIViewController. I've got a class:

class ViewController: UIViewController {
   @IBOutlet var cardButtons: Array<UIButton>

   var flipCount = 0
   var game: CardMatchingGame
   var backCardImage: UIImage
   var frontCardImage: UIImage

   required init(coder aDecoder: NSCoder) {
      self.backCardImage = UIImage(named: "back")
      self.frontCardImage = UIImage(named: "front")
      self.game = CardMatchingGame(count: cardButtons.count, deck: createDeck())

      super.init(coder: aDecoder)
  }

  @IBAction func touchCardButton(sender: UIButton) {
      var cardButtonsArray = cardButtons as NSArray
      var chosenButtonIndex = cardButtonsArray.indexOfObject(sender)
      game.chooseCardAtIndex(chosenButtonIndex)
  }

  func createDeck() -> Deck {
      return PlayingCardDeck()
  }

}

but I've got a error in

count: cardButtons.count >> Variable 'self.cardButtons' used before being initialized/Property 'self.cardButtons' not initialized at super.init call

and

deck: createDeck() >> 'self' used before super.init call

How can I fix this to got properly initialized UIViewController?

Thank you for your help.

LakaLe_
  • 454
  • 1
  • 6
  • 15
  • have you tried to put the line `super.init(coder: aDecoder)` _before_ you try to use the `cardButtons`? because currently you are using it _before_ the class is inited properly. – holex Aug 22 '14 at 11:23

4 Answers4

3

You want to override awakeFromNib and access the outlet there, not in the initialiser.

"The nib-loading infrastructure sends an awakeFromNib message to each object recreated from a nib archive, but only after all the objects in the archive have been loaded and initialized. When an object receives an awakeFromNib message, it is guaranteed to have all its outlet and action connections already established."

So I suggest something like:

class ViewController: UIViewController {
   @IBOutlet var cardButtons: Array<UIButton>!

   var flipCount = 0
   var game: CardMatchingGame!
   var backCardImage: UIImage
   var frontCardImage: UIImage

   required init(coder aDecoder: NSCoder) {
      self.backCardImage = UIImage(named: "back")
      self.frontCardImage = UIImage(named: "front")

      super.init(coder: aDecoder)
  }

  override func awakeFromNib() {
      super.awakeFromNib()
      self.game = CardMatchingGame(count: cardButtons.count, deck: createDeck())
  }

  @IBAction func touchCardButton(sender: UIButton) {
      var cardButtonsArray = cardButtons as NSArray
      var chosenButtonIndex = cardButtonsArray.indexOfObject(sender)
      game.chooseCardAtIndex(chosenButtonIndex)
  }

  func createDeck() -> Deck {
      return PlayingCardDeck()
  }
}
Mike Pollard
  • 10,195
  • 2
  • 37
  • 46
  • Hi, thank you for your answer, but I've still got a error in line super.init(coder: aDecoder). This time I've got 'self.game' not initialized at super.init. – LakaLe_ Aug 22 '14 at 13:37
  • Did you declare it as implicitly unwrapped optional with the ! (`var game: CardMatchingGame!`)? If so you won't get that error. – Mike Pollard Aug 22 '14 at 13:39
0

The outlets in the outlet collection won't be fully available for use until the view that contains them has loaded. Your view controller's viewDidLoad() function will be called once the view has fully loaded into memory. At that point, references to the view such as your outlet collection should be available for use.

So, it'd look something like this:

override func viewDidLoad()
{
    super.viewDidLoad()
    self.game = CardMatchingGame(count: cardButtons.count, deck: createDeck())
}

Further info on viewDidLoad() from Apple's Developer website: viewDidLoad

jefe2000
  • 406
  • 6
  • 13
0

You can just make the method static:

static func createDeck() -> Deck {
    return PlayingCardDeck()
}

and use it like this:

required init(coder aDecoder: NSCoder) {
    self.backCardImage = UIImage(named: "back")
    self.frontCardImage = UIImage(named: "front")
    self.game = CardMatchingGame(count: cardButtons.count, deck: ViewController.createDeck())

    super.init(coder: aDecoder)
}
Pang
  • 9,564
  • 146
  • 81
  • 122
whx
  • 1
-1

As stated here, all variables should be initialized before super.init is called.

Since @IBOutlet is initialized by Interface Builder, an exclamation mark should be fine:

@IBOutlet var cardButtons: Array!

You may also need to add strong: https://stackoverflow.com/a/24686602/3186336

Community
  • 1
  • 1
Damien
  • 660
  • 6
  • 15
  • Hi, thank you for your answer. I've moved super.init() to the first line of initializer but after that I've got another error "self.game not initialized at super.init call" – LakaLe_ Aug 22 '14 at 09:54