0

Basically, I am trying to reset some NSConstraints when the user taps a button.

My constraint outlets:

@IBOutlet weak var firstButtonHeight: NSLayoutConstraint!
@IBOutlet weak var secondButtonheight: NSLayoutConstraint!
@IBOutlet weak var thirdButtonHeight: NSLayoutConstraint!

Example action:

@IBAction func firstButtonHeight(sender: UIButton) {
    firstButtonHeight.constant = 100
}



I thought I could put them into an array (below) and iterate through them before running firstButtonHeight.constant = 100:

var constraints: [NSLayoutConstraint] = [firstButtonHeight, secondButtonheight, thirdButtonHeight]
for constraint in constraints {
    constraint.constant = 50 //Original constraint value
}

However, I get the error Instance member 'firstButtonHeight' cannot be used on type 'ViewController'. When did firstButtonHeight become a ViewController?

nipponese
  • 2,813
  • 6
  • 35
  • 51
  • I'm voting to close this question as off-topic because it is a duplicate of all the other ten million Stack Overflow questions about this same error: http://stackoverflow.com/search?q=+instance+member+cannot+be+used+on+type – matt Mar 07 '16 at 02:56
  • @matt so why answer it? Vote to close it as a relevant dupe and move on instead of droning on about how this is a duplicate. – JAL Mar 07 '16 at 03:16
  • @JAL I _did_ vote to close it. But I had no _single_ canonical post to point to. Besides, the "drone" was my whole point: the OP should have searched first. Also, I have dupe hammer superpowers, so if I picked an actual duplicate, the question would simply have been closed, kaboom; I didn't want to do that. – matt Mar 07 '16 at 03:24

1 Answers1

1

One major problem is that in your constraints initializer you mention the names of other instance variables. You can't do that, because at instance variable initialization time, the instance doesn't exist yet — it is what we are initializing!

You could solve this easily by moving the code into a function that runs after initialization time:

class ViewController: UIViewController {

    @IBOutlet weak var firstButtonHeight: NSLayoutConstraint!
    @IBOutlet weak var secondButtonheight: NSLayoutConstraint!
    @IBOutlet weak var thirdButtonHeight: NSLayoutConstraint!

    func someFunction() {
        var constraints: [NSLayoutConstraint] = [firstButtonHeight, secondButtonheight, thirdButtonHeight]
        for constraint in constraints {
            constraint.constant = 50 //Original constraint value
        }
    }
}

Look carefully at the difference between that and what you've been doing.

A common solution to the problem where you need to mention an instance variable in another instance variable's initializer is to declare the second instance variable lazy. Note that you must use self when you do this (and in general I would recommend always using it). Thus, this compiles at top level of your view controller:

@IBOutlet weak var firstButtonHeight: NSLayoutConstraint!
@IBOutlet weak var secondButtonheight: NSLayoutConstraint!
@IBOutlet weak var thirdButtonHeight: NSLayoutConstraint!
lazy var constraints : [NSLayoutConstraint] = [self.firstButtonHeight, self.secondButtonheight, self.thirdButtonHeight]

But the rest, the for loop, still needs to live inside a function body.

matt
  • 515,959
  • 87
  • 875
  • 1,141
  • I see, that makes sense. But if I want to use `constraints` in multiple actions, then I need to recreate the array for every action or stuff it into another function? – nipponese Mar 07 '16 at 02:50
  • No, I didn't say that. I explained why _your_ code was giving _that_ error. The correct procedure is to _declare_ `constraints` at the top level, but _initialize_ it later. For example, you could solve the problem simply by declaring it `lazy`. I'll add that to my answer. – matt Mar 07 '16 at 02:51