2

I'm going through Apple's iOS development with Swift tutorial and have gotten myself stuck on the 5th stage:

import UIKit

class RatingControl: UIStackView {

    // MARK: Initialisation
    override init(frame: CGRect) {
        super.init(frame: frame)

        setupButtons()
    }

    required init(coder: NSCoder) {
        super.init(coder: coder)

        setupButtons()
    }

    // MARK: Button action
    @objc func ratingButtonTapped(button: UIButton) {
        NSLog("Button pressed")
    }

    // MARK: Private methods
    private func setupButtons() {
        NSLog("setupButtons() called")

        // Create the button
        let button = UIButton()
        button.backgroundColor = UIColor.red

        // Add constraints
        button.translatesAutoresizingMaskIntoConstraints = false
        button.heightAnchor.constraint(equalToConstant: 44.0).isActive = true
        button.widthAnchor.constraint(equalToConstant: 44.0).isActive = true

        // Setup the button action
        button.addTarget(self, action: #selector(RatingControl.ratingButtonTapped(button:)), for: .touchUpInside)

        // Add the button to the stack
        addArrangedSubview(button)
    }
}

setupButtons is called and I see the message in Xcode's debug console, and the button appears as a red box on the simulator: iPhone 8 simulator

However, when I click on the button, nothing happens - no message is printed to the debug console.

I honestly have no clue how I would even begin debugging this, since everything compiles/runs without errors, and I've already tried placing debug messages around what seems to be the issue.

Does anyone have any ideas on what's going on?

EDIT: Here is where the class is being used, and the output in the console: xcode screenshot

konsolas
  • 1,041
  • 11
  • 24

2 Answers2

3

I have tested your code in Playgrounds, and it works as expected. Therefore I expect that you are using the RatingControl incorrectly. One possible bug might be that one of its superviews has isUserInteractionEnabled set to false. Check this example:

// A UIKit based Playground for presenting user interface
import PlaygroundSupport
import UIKit

class RatingControl: UIStackView {

    // MARK: Initialisation
    override init(frame: CGRect) {
        super.init(frame: frame)
        setupButtons()
    }

    required init(coder: NSCoder) {
        super.init(coder: coder)
        setupButtons()
    }

    // MARK: Button action
    @objc func ratingButtonTapped(button: UIButton) {
        print("Button pressed")
    }

    // MARK: Private methods
    private func setupButtons() {
        print("setupButtons() called")

        // Create the button
        let button = UIButton()
        button.backgroundColor = UIColor.red

        // Add constraints
        button.translatesAutoresizingMaskIntoConstraints = false
        button.heightAnchor.constraint(equalToConstant: 44.0).isActive = true
        button.widthAnchor.constraint(equalToConstant: 44.0).isActive = true

        // Setup the button action
        button.addTarget(self, action: #selector(RatingControl.ratingButtonTapped(button:)), for: .touchUpInside)

        // Add the button to the stack
        addArrangedSubview(button)
    }
}

class A: UIViewController {

    override func viewDidLoad() {
        super.viewDidLoad()

        self.view.addSubview(RatingControl(frame: CGRect(x: 0, y: 0, width: 40, height: 40)))
        // if you uncomment the following line, the button will stop working
//        self.view.isUserInteractionEnabled = false
    }
}

// Present the view controller in the Live View window
PlaygroundPage.current.liveView = A()

If that's not the case, include the code in which you use the RatingControl, because that's where the bug lies.

Milan Nosáľ
  • 19,169
  • 4
  • 55
  • 90
  • I use RatingControl from Main.storyboard as the class of a stack view. Everything in the view seems pretty simple so I don't think anything is overlaying it... I added a screenshot in the question – konsolas Jan 28 '18 at 14:43
  • @konsolas it's not about overlaying views, but about superviews.. if you put `RatingControl` as a subview to another `stackView`, and that `stackView` has `isUserInteractionEnabled` set to false, the buttons won't get touch events.. same applies to the `RatingControl` itself - make sure that `RatingControl` has `isUserInteractionEnabled` checked – Milan Nosáľ Jan 28 '18 at 14:47
  • 1
    I rechecked the storyboard and it looks like I had a random stack view around it that wasn't doing anything - the button works after I removed it. – konsolas Jan 29 '18 at 18:04
  • superview isUserInteractionEnabled was false in my case, thanks for your suggestion @MilanNosáľ. – Faraz Ahmed Khan Apr 26 '22 at 19:25
0

It's working normally with me, I've put self.view.addSubview(button) instead of addArrangedSubview(button) .

Darko
  • 615
  • 7
  • 21
  • 1
    That doesn't seem possible for me - the view property doesn't exist in UIStackView – konsolas Jan 28 '18 at 12:35
  • True, but that should give you a clue why your code isn't working. I see that you're adding arranged subview but to nothing. Maybe you should use yourStackViewName.addArrangedSubview(button) ? Check this thread https://stackoverflow.com/questions/30728062/add-views-in-uistackview-programmatically – Darko Jan 28 '18 at 12:41