0

I won't get to into the weeds on what my app is ultimately doing but the issue I'm having is when I click on one of 6 button that all have a UIImage in their imageView I then try to reference the image name (the images are coming from my assets) to switch over which button was pressed and use the results to update a label.

The values are being set and printing out in the action, however the switch statement always falls through to default and I can't figure out why. Are the button imageViews effecting the image names?

@IBOutlet var feelingLabel: UILabel!

var feelingImage: UIImage? {
    didSet {
        switch feelingImage {
        case UIImage(named: "happyFace"):
            self.feelingLabel.text = "feeling happy"
        case UIImage(named: "fineFace"):
            self.feelingLabel.text = "feeling fine"
        case UIImage(named: "angryFace"):
            self.feelingLabel.text = "feeling angry"
        case UIImage(named: "anxiousFace"):
            self.feelingLabel.text = "feeling anxious"
        case UIImage(named: "sadFace"):
            self.feelingLabel.text = "feeling sad"
        case UIImage(named: "sickFace"):
            self.feelingLabel.text = "feeling sick"
        default:
            self.feelingLabel.text = "feeling..."
        }
    }
}

// all six buttons are connected to this action 
@IBAction func feelingButtonTapped(_ sender: UIButton) {
    guard let selectedFeelingImage = sender.imageView?.image,
          selectedFeelingImage != self.feelingImage else {
        self.feelingImage = nil
        return
    }
    self.feelingImage = selectedFeelingImage
    print(selectedFeelingImage)
    print(self.feelingImage)
}
rBalmer
  • 67
  • 9
  • Does this answer your question? [How to compare two UIImage objects](https://stackoverflow.com/questions/11342897/how-to-compare-two-uiimage-objects) – aheze Aug 03 '21 at 05:42

2 Answers2

1

If you want to compare images, you need to convert them to Data as following:

var feelingImage: UIImage? {
didSet {
    switch feelingImage!.pngData() {
    case UIImage(named: "happyFace")!.pngData():
        self.feelingLabel.text = "feeling happy"
    case UIImage(named: "fineFace")!.pngData():
        self.feelingLabel.text = "feeling fine"
    case UIImage(named: "angryFace")!.pngData():
        self.feelingLabel.text = "feeling angry"
    case UIImage(named: "anxiousFace")!.pngData():
        self.feelingLabel.text = "feeling anxious"
    case UIImage(named: "sadFace")!.pngData():
        self.feelingLabel.text = "feeling sad"
    case UIImage(named: "sickFace")!.pngData():
        self.feelingLabel.text = "feeling sick"
    default:
        self.feelingLabel.text = "feeling..."
    }
}

}

Mr.SwiftOak
  • 1,469
  • 3
  • 8
  • 19
1

A UIImage does not have a "name" ... your image resource does, and that's what you are using to load the image. However, once it is loaded, there is no association with the resource name.

While comparing the .pngData may work, it would be a very inefficient approach.

One very good approach would be to track your buttons in an array, and use the array index to determine which button was tapped.

Another approach would be to subclass UIButton and add your own .imageName property.

For example:

class NamedButton: UIButton {
    var imageName: String = ""
}

Now, in code, your button creating becomes:

    if let img = UIImage(named: "happyFace") {
        let btn = NamedButton()
        btn.setImage(img, for: [])
        btn.imageName = "happyFace"
        btn.addTarget(self, action: #selector(feelingButtonTapped(_:)), for: .touchUpInside)
    }

your "current selection" can be:

var feelingImageName: String = "" {
    
    didSet {
        switch feelingImageName {
        case "happyFace":
            self.feelingLabel.text = "feeling happy"
        case "fineFace":
            self.feelingLabel.text = "feeling fine"
        case "angryFace":
            self.feelingLabel.text = "feeling angry"
        case "anxiousFace":
            self.feelingLabel.text = "feeling anxious"
        case "sadFace":
            self.feelingLabel.text = "feeling sad"
        case "sickFace":
            self.feelingLabel.text = "feeling sick"
        default:
            self.feelingLabel.text = "feeling..."
        }
    }

}

and your button action can be:

@IBAction func feelingButtonTapped(_ sender: UIButton) {
    
    guard let btn = sender as? NamedButton,
          btn.imageName != self.feelingImageName else {
        self.feelingImageName = ""
        return
    }
    self.feelingImageName = btn.imageName
    print(btn.imageName)
    print(self.feelingImageName)

}

If you are using Storyboard / Interface Builder for your layout, you can make the .imageName property @IBInspectable so you can set it at design-time:

class NamedButton: UIButton {
    @IBInspectable var imageName: String = ""
}

enter image description here

DonMag
  • 69,424
  • 5
  • 50
  • 86
  • Thank you so much for such a concise answer (not always the case on here!). The .pngData() approach worked as well and obviously a lot quicker but I love how this is structured. I am using interface builder and the whole `inspectable` thing is new to may as well, so again thanks for that. – rBalmer Aug 03 '21 at 16:15
  • Once the button has been selected and the label is updated I am then passing the image into a User property. I'm guessing I can still just take the button image in the button action? – rBalmer Aug 03 '21 at 16:23
  • 1
    @rBalmer - tough to say... normally, instead of storing an actual `UIImage` as a property of a "user" object, you would add an `imageName` property and load/display the image when needed ... For example, if you are saving User-data to a database, it is much easier to store the image name as a string, rather than trying to save the *data* of the image. – DonMag Aug 03 '21 at 16:49
  • Thanks @DonMag. I ended creating a new struct for the user "feeling" property which holds both an image and name property. In the action button I created the feelingImage which is now the new feeling type and populated it with the NamedButton.imageName and the NamedButton.image. Now I can switch over the name string as you suggested without having to reload the pngData every time and I am also able to access the image itself when needed. Based on what I am doing moving forward, having that name from the NamedButton attached to the property will end up being really helpful, so again thank you. – rBalmer Aug 03 '21 at 17:06