Search code examples
swiftfunctionuibuttontagssender

How to call a specific UIButton by tag other than the sender?


In a simple memory game I have a struct that defines the two cards that are tapped and returns in mutating functions the integers firstFlippedCard and secondFlippedCard.

If these do not match by another property, I want both cards to 'flip back'. I made a transition function for this - however, I can only make the last tapped button to switch back using the following logic:

    @IBAction func cardsPress(_ sender: UIButton) {

        flip(sender: sender)

        if cardBrain.checkFirstCard(card: sender.tag - 1) == true {
            //stay flipped
        } else if cardBrain.checkForMatch(card: sender.tag - 1).match == true {
            //stay flipped
        } else {
            DispatchQueue.main.asyncAfter(deadline: .now() + .seconds(1), execute:  {
                self.backFlip(sender: sender)
            })
        }


    }

Note that multiple UIButtons are linked to cardsPress. How can I make them both flip back instead of only the sender?


Solution

  • Add a property to keep track of the previousButton pressed. Then use this property to flip both the current sender and the previousButton. Finally, set previousButton back to nil after flipping it or deciding to keep it flipped.

    var previousButton: UIButton?
    var waitForFlip = false
    
    @IBAction func cardsPress(_ sender: UIButton) {
    
        // ignore button input while waiting for cards to unflip
        guard !waitForFlip else { return }
    
        flip(sender: sender)
    
        if cardBrain.checkFirstCard(card: sender.tag - 1) {
            //stay flipped
            previousButton = sender
        } else if cardBrain.checkForMatch(card: sender.tag - 1).match  {
            //stay flipped
            previousButton = nil
        } else {
            waitForFlip = true
            DispatchQueue.main.asyncAfter(deadline: .now() + .seconds(1), execute:  {
                self.backFlip(sender: sender)
                if let button = previousButton {
                    self.backFlip(sender: button)
                    self.previousButton = nil
                }
                self.waitForFlip = false
            })
        }
    
    }
    

    Notes:

    • There is a possibility that the player could start flipping another card before the previous ones flip back. I introduced a waitForFlip property to ignore button inputs while we are waiting for the mismatched cards to flip back to avoid an issue where previousButton gets set and then overwritten to nil by the previous unflip.

    • There is no need to check if a Bool value is == true. Simply check if boolValue { instead of if boolValue == true. I removed two instances of that.

    • You might want to disable the buttons of cards that have been flipped (set sender.isEnabled = false) to keep the player from selecting a flipped card. Remember to reenable them again when they are flipped back by setting their isEnabled properties to true.