Shinforinpola
Shinforinpola

Reputation: 218

IBoutlet Connected From SuperClass UIView Still Nil

I work with Nibs. I have two screens that will use the "same" UIView component with the same behavior. It's not the same component because in each screen i placed a UIView and made the same configuration, as show on the image.

The two Screens

To solve this and prevent replicate the same code in other classes i wrote one class, that is a UIView subclass, with all the functions that i need.

After that i made my custom class as superclass of these UIView components to inherit the IBOutlets and all the functions.

Added as SuperClass of UIView Components

Custom superclass add success

My custom class is not defined in a Nib, is only a .swift class.

I made all the necessary connections but at run time the IBOutlets is Nil.

IBOutlets Connected

Connections on View

Connections on UITableViewCell

The code of my custom class:

class FeelingGuideView: UIView {

    @IBOutlet weak var firstScreen: UILabel!
    @IBOutlet weak var secondScreen: UILabel!
    @IBOutlet weak var thirdScreen: UILabel!
    @IBOutlet weak var fourthScreen: UILabel!

    private var labelsToManage: [UILabel] = []
    private var willShow: Int!
    private var didShow: Int!

    override init(frame: CGRect) {
        super.init(frame: frame)

        self.initLabelManagement()
    }

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

        self.initLabelManagement()
    }

    private func initLabelManagement() {
        self.initLabelVector()
        self.willShow = 0
        self.didShow = 0
        self.setupLabelToShow(label: labelsToManage[0])
        self.setupLabels()
    }

    private func initLabelVector() {
        self.labelsToManage.append(self.firstScreen)
        self.labelsToManage.append(self.secondScreen)
        self.labelsToManage.append(self.thirdScreen)
        self.labelsToManage.append(self.fourthScreen)
    }

    private func setupLabels() {

        for label in labelsToManage {
            label.layer.borderWidth = 2.0
            label.layer.borderColor = UIColor(hex: "1A8BFB").cgColor
        }
    }

    func willShowFeelCell(at index: Int) {
        self.willShow = index

        if willShow > didShow {
            self.setupLabelToShow(label: labelsToManage[willShow])
        }
        else if willShow < didShow {

            for i in didShow ... willShow + 1 {

                let label = labelsToManage[i]
                self.setupLabelToHide(label: label)
            }
        }
    }

    private func setupLabelToShow(label: UILabel) {
        label.textColor = UIColor.white
        label.backgroundColor = UIColor(hex: "1A8BFB")
    }

    private func setupLabelToHide(label: UILabel) {
        label.textColor = UIColor(hex: "1A8BFB")
        label.backgroundColor = UIColor.white
    }
}

I found this question similar to mine: Custom UIView from nib inside another UIViewController's nib - IBOutlets are nil

But my UIView is not in a nib.

EDIT:

I overrided the awakeFromNib but it neither enter the method.

More explanation:

My custom class is only superClass of this component:

Custom UIView

Which i replicate on two screens.

One screen is a UITableViewCell and the another a UIViewController.

It's all about to manage the behavior of the labels depending on the screen that is showing at the moment on the UICollectionView

When the initLabelVector() function is called at the required init?(coder aDecoder:) it arrises a unwrap error:

Error

The error when try to open the View:

enter image description here

Cannot show the error with the UITableViewCell because it is called at the beginning of the app and don't appear nothing. To show the error with the screen i needed to remove the call of the UITableViewCell.

The UITableViewCell is registered first with the tableView.register(nib:) and after using the tableView.dequeueReusebleCell.

The UIViewController is called from a menu class that way:

startNavigation = UINavigationController(rootViewController: FellingScreenViewController())
appDelegate.centerContainer?.setCenterView(startNavigation, withCloseAnimation: true, completion: nil)

Upvotes: 1

Views: 1149

Answers (2)

matt
matt

Reputation: 534885

The problem is this code:

required init?(coder aDecoder: NSCoder) {
    super.init(coder: aDecoder)
    self.initLabelManagement()
}

The trouble is that init(coder:) is too soon to speak of the view's outlets, which is what initLabelManagement does; the outlets are not hooked up yet. Put this instead:

required init?(coder aDecoder: NSCoder) {
    super.init(coder: aDecoder)
}
override func awakeFromNib() {
    super.awakeFromNib()
    self.initLabelManagement()
}

How I arrived at this answer:

As a test, I tried this:

class MyView : UIView {
    @IBOutlet var mySubview : UIView!
    required init?(coder aDecoder: NSCoder) {
        super.init(coder:aDecoder)
        print(#function, self.mySubview)
    }
    override func awakeFromNib() {
        super.awakeFromNib()
        print(#function, self.mySubview)
    }
}

Here's the output:

init(coder:) nil
awakeFromNib() <UIView: 0x7fc17ef05b70 ... >

What this proves:

  • init(coder:) is too soon; the outlet is not hooked up yet

  • awakeFromNib is not too soon; the outlet is hooked up

  • awakeFromNib is called, despite your claim to the contrary

Upvotes: 4

Shinforinpola
Shinforinpola

Reputation: 218

When the init() from my custom class is called the IBOutlets are not hooked up yet.

So, I created a reference on the parent view and called the iniLabelManagement() from the viewDidLoad() method and everything worked.

Thank you matt, for the help and patience!

Upvotes: 1

Related Questions