title: Swift 4: didSet @IBOutlet calls viewDidLayoutSubviews, but not with addSubview()
body: <p>When <code>selectCard</code> is called, by commenting out various parts of the code I've discovered that <code>viewDidLayoutSubviews</code> is only called when <code>score</code> is updated in <code>checkIfCardsMatch</code> function. The score is only updated if we have <code>matchedCards</code>. Why is this happening? </p>
  
  <p>I would like to have <code>viewDidLayoutSubviews</code> called every time <code>selectCard</code> is called. I noticed if I add <code>CardTable.addSubview(grid)</code> to my <code>resetTable</code> function than <code>viewDidLayoutSubviews</code> is called every time <code>selectCard</code> is called EXECPT when score is changed.</p>
  
  <p>What is going on here and how can I make sure <code>viewDidLayoutSubviews</code> is called on each card selection?</p>
  
  <pre><code>// Score
      @IBOutlet weak var scoreLabel: UILabel! {
          didSet {
              scoreLabel.text = "Score: \(score)"
          }
      }
      private var score = 0 {
          didSet {
              scoreLabel.text = "Score: \(score)"
          }
      }
  
      func selectCard(card: Card) {
          // must deal more cards if we have a match first
          if !matched.isEmpty &amp;&amp; !game.cards.isEmpty {
              print("must deal more cards if we have a match first")
              resetTable()
              return
          }
  
          // deal no longer possible
          if !matched.isEmpty &amp;&amp; game.cards.isEmpty {
              print("deal no longer possible")
              clearAndDeal()
          }
  
          // reset any mismatched card styles
          if !misMatched.isEmpty {
              print("reset any mismatched card styles")
              resetMisMatchedStyle()
          }
  
          // select or deselect card
          game.select(card: card)
          if let idx = visibleCards.index(of: card){
              visibleCards[idx].state = .selected
          }
  
          // check for match
          checkIfCardsMatch()
          // resetTable
          resetTable()
      }
  
      private func resetTable(){
          grid = CardTableView(frame: CardTable.bounds, cardsInPlay: visibleCards)
          grid.delegate = self
      }
  
      private func checkIfCardsMatch(){
          if let matchedCards = game.matchedCards() {
              print("MATCHED!", matchedCards)
              matched = matchedCards
              game.clearSelectedCards()
              score += 3
              // set visible cards to matched
              for card in matched {
                  if let idx = visibleCards.index(of: card){
                      visibleCards[idx].state = .matched
                  }
              }
          }else {
              if game.selectedCards.count == 3 {
                  print("no match")
                  misMatched = game.selectedCards
                  game.clearSelectedCards()
                  score -= 5
                  for card in misMatched {
                      if let idx = visibleCards.index(of: card){
                          visibleCards[idx].state = .misMatched
                      }
                  }
              }
          }
  </code></pre>
  
  <h2>        }</h2>
  
  <p>The whole file:</p>
  
  <pre><code>//
  //  ViewController.swift
  //  Set
  //
  
  import UIKit
  
  class ViewController: UIViewController, CardTableViewDelegate {
      func delegateCardTap(card: Card){
          print("called in view controller")
          selectCard(card: card)
      }
      // Game
      private var game = SetGame()
      private lazy var grid = CardTableView(frame: CardTable.bounds, cardsInPlay: visibleCards)
      // table to place all cards
      @IBOutlet weak var CardTable: UIView! {
          didSet {
              // set up buttons with 12 cards
              initalDeal()
          }
      }
      @IBAction func newGame(_ sender: UIButton) {
          score = 0
          game = SetGame()
          visibleCards.removeAll()
          matched.removeAll()
          misMatched.removeAll()
          dealMoreButton.isEnabled = true
          dealMoreButton.setTitleColor(#colorLiteral(red: 0.231372549, green: 0.6, blue: 0.9882352941, alpha: 1), for: .normal)
          initalDeal()
          grid.cards = visibleCards
      }
  
      override func viewDidLoad() {
          grid.delegate = self
      }
  
      override func viewDidLayoutSubviews() {
          print("viewDidLayoutSubviews")
          super.viewDidLayoutSubviews()
          // reset frame when device rotates
          grid.frame = CardTable.bounds
  
          // add cards to the card table
          CardTable.addSubview(grid)
      }
      // Cards
      private var visibleCards = [Card]()
  
      // Score
      @IBOutlet weak var scoreLabel: UILabel! {
          didSet {
              scoreLabel.text = "Score: \(score)"
          }
      }
      private var score = 0 {
          didSet {
              scoreLabel.text = "Score: \(score)"
          }
      }
  
      // Deal
      @IBOutlet weak var dealMoreButton: UIButton!
      @IBAction func deal(_ sender: UIButton) {
          // have a match and cards available to deal
          if !matched.isEmpty &amp;&amp; !game.cards.isEmpty {
              //TODO: fix this for new UI
              clearAndDeal()
          } else {
              dealThreeMore()
          }
          // disable if we run out of cards
          if game.cards.isEmpty {
              disable(button: sender)
          }
          grid.cards = visibleCards
      }
      private func dealThreeMore(){
          if visibleCards.count &lt; game.cardTotal {
              for _ in 0..&lt;3 {
                  if let card = game.drawCard() {
                      // add more visible cards
                      visibleCards.append(card)
                  } else {
                      print("ran out of cards in the deck!")
                  }
              }
          }
      }
      private func disable(button sender: UIButton){
          sender.isEnabled = false
          sender.setTitleColor(#colorLiteral(red: 0.5, green: 0.5, blue: 0.5, alpha: 1), for: .normal)
      }
      private func clearAndDeal(){
          print("in clearAndDeal")
          //TODO: rewrite me
          for card in matched {
              if let index = visibleCards.index(of: card){
                  // remove matched styles
                  // draw new card
                  if let newCard = game.drawCard() {
                      // swap with old card
                      replace(old: index, with: newCard)
                  } else {
                      // ran out of cards in the deck!
                      hideButton(by: index)
                  }
              }
          }
          matched.removeAll()
      }
  
      private var allCardsMatched: Bool {
          let cards = visibleCards.filter({card in
              //            if let index = visibleCards.index(of: card){
              ////                return cardButtons[index].isEnabled
              //            }
              return false
          })
          return cards.count == 3
      }
      private var misMatched = [Card]()
      private var matched = [Card]()
  
      func selectCard(card: Card) {
          // must deal more cards if we have a match first
          if !matched.isEmpty &amp;&amp; !game.cards.isEmpty {
              print("must deal more cards if we have a match first")
              resetTable()
              return
          }
  
          // deal no longer possible
          if !matched.isEmpty &amp;&amp; game.cards.isEmpty {
              print("deal no longer possible")
              clearAndDeal()
          }
  
          // reset any mismatched card styles
          if !misMatched.isEmpty {
              print("reset any mismatched card styles")
              resetMisMatchedStyle()
          }
  
          // select or deselect card
          game.select(card: card)
          if let idx = visibleCards.index(of: card){
              visibleCards[idx].state = .selected
          }
  
          // check for match
          checkIfCardsMatch()
          // resetTable
          resetTable()
      }
  
      private func resetTable(){
          grid = CardTableView(frame: CardTable.bounds, cardsInPlay: visibleCards)
          grid.delegate = self
      }
  
      private func checkIfCardsMatch(){
          if let matchedCards = game.matchedCards() {
              print("MATCHED!", matchedCards)
              matched = matchedCards
              game.clearSelectedCards()
              score += 3
              // set visible cards to matched
              for card in matched {
                  if let idx = visibleCards.index(of: card){
                      visibleCards[idx].state = .matched
                  }
              }
          }else {
              if game.selectedCards.count == 3 {
                  print("no match")
                  misMatched = game.selectedCards
                  game.clearSelectedCards()
                  score -= 5
                  for card in misMatched {
                      if let idx = visibleCards.index(of: card){
                          visibleCards[idx].state = .misMatched
                      }
                  }
              }
          }
      }
  
      private func initalDeal(){
          for _ in 0..&lt;12 {
              if let card = game.drawCard() {
                  visibleCards.append(card)
              }
          }
      }
  
      private func removeStyleFrom(button: UIButton){
          button.layer.backgroundColor = #colorLiteral(red: 1.0, green: 1.0, blue: 1.0, alpha: 1.0)
      }
  
      private func resetMisMatchedStyle(){
          for card in misMatched {
              if let idx = visibleCards.index(of: card){
                  visibleCards[idx].state = nil
              }
          }
          misMatched.removeAll()
      }
  
      private func replace(old index: Int, with newCard: Card){
          visibleCards[index] = newCard
          //        style(a: cardButtons[index], by: newCard)
      }
  
      private func hideButton(by index: Int){
          //        let button = cardButtons[index]
          //        button.setAttributedTitle(NSAttributedString(string:""), for: .normal)
          //        button.backgroundColor = #colorLiteral(red: 1, green: 1, blue: 1, alpha: 0)
          //        button.isEnabled = false
      }
  
      private func styleTouched(button: UIButton, by card: Card) {
          if game.selectedCards.contains(card) {
              button.layer.backgroundColor = #colorLiteral(red: 0.9848672538, green: 0.75109528, blue: 1, alpha: 1)
          }else {
              removeStyleFrom(button: button)
          }
      }
  }
  </code></pre>