Randy Le
Randy Le

Reputation: 45

Is there a way to grab the parent object from a subview?

I'm working on a crossword puzzle app for swift and I am having trouble getting a UIButton from a subview in the UIButton that is a textfield.

The text field takes up the space where the UIButton title should be, but when clicking on the textfield it doesn't click the UIButton. The UIButton itself as of now, highlights all the UIButtons of the some column and row.

There a few things I've tried such as graving the superclass of the subview

var myButton: CustomButton = textfield.superclass as? CustomButton

and I also tried using

var myObject : CustomButton? {
  return view.compactMap({$0 as? CustomButton }).first
}

In the CustomButton.swift

class CustomButton: UIButton {
    var number: Int = 0
    var letter: Character?
    var textField: UITextField!
    var cornerLabel: UILabel!

    // this init will intialize the button through programatically
    override init(frame: CGRect) {
        super.init(frame: frame)

        textField = UITextField(frame: CGRect(x: 0, y: 0, width: 50, height: 50))
        textField.translatesAutoresizingMaskIntoConstraints = false
        textField.center = .zero
        textField.textAlignment = .center
        textField.text = ""

I have a ButtonStore.swift that stores all the CustomButtons in the array so I can manage them and retrieve certain ones.

And the MainController.swift has all the reference CustomButton. I am using a UITextFieldDelegate from the MainController

class MainController : UIViewController, UITextFieldDelegate{
    var buttonStore : ButtonStore!

    @IBOutlet var A1 : CustomButton!

    @IBAction func buttonIsPress(sender: CustomButton){
        let button : CustomButton = sender
        let identifier : String = sender.accessibilityIdentifier ?? ""
        // Clear all backgroundbox back to white unless the background is black
        buttonStore.removeHighlights()
        // Highlight the button pressed and its column and row
        buttonStore.highlightRowColumn(identifier: identifier)
    }

    func textFieldShouldBeginEditing(_ textField: UITextField) -> Bool 
    {
        print("something happened")
        // TRIED RECEIVING THE CUSTOMBUTTON HERE
        return true
    }

The expected result is to have had the CustomButton trigger when textfield is pressed or grabbing the CustomButton of the textfield pressed so I use the CustomButton as reference.

Upvotes: 2

Views: 165

Answers (2)

Josh Homann
Josh Homann

Reputation: 16347

You can grab any superview or any parent view controller generically in a type safe way by walking up the responder chain (because both UIViewController and UIView inherit from UIResponder and implement its next method):

extension UIResponder {
    func firstParent<T: UIResponder>(ofType type: T.Type ) -> T? {
        return next as? T ?? next.flatMap { $0.firstParent(ofType: type) }
    }
}

Use like:

if let button = textField.firstParent(ofType: CustomButton.self) {
  //Do button stuff here
}

This method has the advantage that you can find the next parent of a particular type even if it isn't the immediate parent (ie you may have several views between the textfield and the CustomButton and this still works, while calling superview does not).

Upvotes: 1

Razi Tiwana
Razi Tiwana

Reputation: 1435

You can get the superview by

if let button = textField.superview as? CustomButton {
   // Do what you want to here
}

Upvotes: 1

Related Questions