3

I currently have a function that gathers a time from a database and returns it for other functions to use. It needs a parameter, which is stored in another part of the app, in order to gather the value from the database.

My problem comes when I want to call this function within an IBAction function.

Here is my code for the function:

func getDBValue(place: GMSPlace) -> Int {

    var expectedValue = 0

    databaseRef.child("values").child(place.placeID).observe(.value, with: { (snapshot) in
        let currentValue = snapshot.value as? [Int]

        if currentValue == nil {
            self.noValue()
            expectedValue = 0
        } else {
            let sumValue = currentValue?.reduce(0, +)

            let avgValue = sumValue! / (currentValue?.count)!

            print("The current value is \(String(describing: avgValue))")

            expectedValue = avgValue

            self.valueLabel.text = String(describing: avgValue)
        }

    })

    print("This is the expected WT: \(expectedWaitTime)")

    return expectedValue

}

And here is my code for my IBAction function that is having issues with multiple parameters:

@IBAction func addValuePressed(_ sender: Any, place: GMSPlace) {

    print("This is the place ID: \(place.placeID)")

    var expectedValue = getDBValue(place: place)

    expectedValue = expectedValue + 1

    print("The expectedValue is now: \(expectedValue)")

    self.valueLabel.text = String(describing: expectedValue)

}

This gives me a libc++abi.dylib: terminating with uncaught exception of type NSException (lldb) error. After some testing, it seems that the error is caused by the added parameter place: GMSPlace in my IBAction function. Any thoughts on how to fix this?

bwc
  • 1,732
  • 1
  • 14
  • 27
  • You cannot add parameters to an IBAction. Period. The usual workarounds, depending on your needs, are (1) use the tag property (it's an `Int`) to indicate which sender was called, or (2) make your `GMSPlace` instance available inside the IBAction. –  Apr 24 '17 at 15:15

1 Answers1

9

IBAction methods cannot have arbitrary signatures. You cannot add an extra parameter here. There's no way for the button to send you this (how does the button know what place is?) Generally this is handled either by there only being one UI element pointing to this action (so you know what button was pressed), or using a tag on the sender to identify it. Every view has a tag property that's just an integer. You can set that in Interface Builder or in code, and then you can read it to identify the sender.

Start by reading over Target Action in the docs that explains how this works on the various platforms. In general, the signature of an IBAction must be:

@IBAction func action(_ sender: Any)

However, on iOS, it may also be:

@IBAction func action(_ sender: Any, forEvent: UIEvent)

As Taylor M points out below, you can also have use this signature (though I can't remember right off hand if this works outside of iOS; I've only personally used it there).

@IBAction func action()

But that's it. There are no other allowed signatures.

Rob Napier
  • 286,113
  • 34
  • 456
  • 610
  • 1
    You can also have `@IBAction func doSomething()` with no parameters. – Taylor M Apr 24 '17 at 16:17
  • In Xcode 9.2/iOS 11.2, the following signatures also work: 1) `@IBAction func doStuff(_ sender: UIButton)`, i.e. the type of the parameter can be the type of the actual control--the type does not have to be Any. 2) `@IBAction func doStuff(sender: Any)` -- in the Connections Inspector for the ViewController the method name will be listed as doStuffWithSender:. – 7stud Jan 17 '18 at 07:36