0

I have a lot of experience working with Matlab, but I only recently started programming in Swift 4. My current project involves building a questionnaire. I have used the ‘drag and drop’ feature in Xcode to produce an @IBAction function for a button in storyboard, which can then lead to pressed button changing its appearance. This functionality is contained within the ButtonResponse class in the code snippet below:

    struct ResponseProfile {

       var responseArray: Array<String>
       init(responseArray: Array<String>) {
            self.responseArray = ["unchecked","unchecked","unchecked","unchecked","unchecked","unchecked","unchecked"]
        }

        mutating func updateArray(_ anArray: Array<String>) -> (Array<String>) {
            responseArray = anArray
            return responseArray
        }

    }

    class ButtonResponse: UIButton {

        var responseVariables: ResponseProfile

        var checkedImage = UIImage(named: "checkedResponseBox")! as UIImage
        var uncheckedImage = UIImage(named: "uncheckedResponseBox")! as UIImage

        required init?(coder aDecoder: NSCoder) {
            self.responseVariables = ResponseProfile(
                responseArray: []
            )
            super.init(coder: aDecoder)
        }


        @IBAction func checkboxTapped(_ sender: UIButton) {
            switch sender.accessibilityIdentifier {
                case "excellent":

                    let oldResponseStatus = responseVariables.responseArray[0]
                    if oldResponseStatus == "unchecked"{
                        sender.setImage(checkedImage, for: UIControlState.normal)
                        let oldResponsePresence = responseVariables.responseArray.contains("checked")

                        if oldResponsePresence == true {
                            responseVariables.responseArray = ["unchecked","unchecked","unchecked","unchecked","unchecked","unchecked","unchecked"]
                        }
                        responseVariables.responseArray[0] = "checked"
                    } else if oldResponseStatus == "checked" {
                        sender.setImage(uncheckedImage, for: UIControlState.normal)
                        responseVariables.responseArray[0] = "unchecked"
                }

                case "veryGood":
                    let oldResponseStatus = responseVariables.responseArray[1]
                    if oldResponseStatus == "unchecked" {
                        sender.setImage(checkedImage, for: UIControlState.normal)
                        let oldResponsePresence = responseVariables.responseArray.contains("checked")
                        if oldResponsePresence == true {
                            responseVariables.responseArray = ["unchecked","unchecked","unchecked","unchecked","unchecked","unchecked","unchecked"]
                        }
                        responseVariables.responseArray[1] = "checked"
                    } else if oldResponseStatus == "checked" {
                        sender.setImage(uncheckedImage, for: UIControlState.normal)
                        responseVariables.responseArray[1] = "unchecked"
                    }

                default: break

            }
        }

    }

I imagined that I could use an array to internally represent the state of the buttons in the user interface (this would be the ‘responseArray’ variable). By changing elements within responseArray following a button press, I thought I could keep track which buttons were pressed and ensure that no more than one button at a time was checked. I incorrectly thought responseArray would be updated, but this is not the case. The array always reverts to its initiation state.

N.B. responseArray contains seven elements because there are seven response options. So far, I have attempted to program only two of the response options: “excellent” and “veryGood”.

In attempting to find a solution, I attempted to simplify the above code in playground:

import UIKit

    struct ResponseProfile {
        var responseArray: Array<String>
        init(responseArray: Array<String>) {
            self.responseArray =     ["unchecked","unchecked","unchecked","unchecked","unchecked","unchecked","unchecked"]
        }
        mutating func updateArray(input anArray: Array<String>) -> (Array<String>) {
            responseArray = anArray
            return responseArray
        }
    }

    class ButtonResponse {
        var responseVariables: ResponseProfile
        init(){
            self.responseVariables = ResponseProfile(responseArray: [])
        }
        var responseA = ResponseProfile(responseArray: [])

    }

    var responseOne = ResponseProfile(responseArray: [])
    responseOne.responseArray[0] = "checked" //user performs action resulting in first element being changed from a starting value of "unchecked" to "checked"
    responseOne.updateArray(input: responseOne.responseArray)

    var responseTwo = ResponseProfile(responseArray:[])
    responseTwo.responseArray //responseArray revert to initialization values. How can I keep changes to the responseArray?

How can I update responseArray within the ResponseProfile structure without having to create a new variable to record every change? Is this the problem I should be looking at or is there, on a more general level, a better strategy that I should be taking?

I am surprised that I struggled this much to deal with this issue. I thought the answer would be clear if I read the relevant parts of the documentation and studied some example code. All the example code I found was too simplistic and focused on just one iteration of updating the array.

Any comments or suggestions would be much appreciated!

cjg
  • 3
  • 2

2 Answers2

0

Looking at your playground code, I found that you are passing a blank [] array to argument of ResponseProfile struct during init. and it is always initialising your responseArray.

If you want to pass the things by reference, you can change Response profile to class and there you can achieve the similar functionalities and use inout parameter to keep the same array without using the function updateArray.

The example I am showing here is for the class and objects of class can be pass by reference. thus keep your previous changes.

var responseTwo = ResponseProfile(responseArray:[])

If you wants to keep the old response, you can pass that array as an argument

var responseTwo = ResponseProfile(responseArray:responseOne.responseArray)

OR

var responseTwo = responseOne

Will keep the responseArray.

You can read more about it, at official blog

Also you can this post with more insight for the case.

Hope it helps.

Bhavin Kansagara
  • 2,866
  • 1
  • 16
  • 20
0

Thanks for your response Bhavin. By passing responseArray by reference (as Bhavin suggests) to the necessary class (which has turned out to be the ButtonResponse class rather than ResponseProfile), I can give responseArray an initial value. I then use the buttonPress function to update responseArray. See below:

class ButtonResponse: Responses {
var responseArray: [String]
init (responseArray: [String]) {
    self.responseArray = responseArray
}

func buttonPress(inputString: String, targetIndex: Int) -> [String] {
    //need guard statement to block function when targetIndex > number of elements in responseArray
    responseArray[targetIndex] = inputString
    return responseArray
}
}

let initiateResponseArray = 

["unchecked","unchecked","unchecked","unchecked","unchecked","unchecked","unchecked"]
var doPress = ButtonResponse(responseArray: initiateResponseArray)
doPress.buttonPress(inputString: "checked", targetIndex: 0)
var getPressInfo1 = doPress.responseArray
print(getPressInfo1)
//prints: ["checked", "unchecked", "unchecked", "unchecked", "unchecked", "unchecked", "unchecked"]
doPress.buttonPress(inputString: "checked", targetIndex: 1)
var getPressInfo2 = doPress.responseArray
print(getPressInfo2)
//prints: ["checked", "checked", "unchecked", "unchecked", "unchecked", "unchecked", "unchecked"]

I am still unsure how to implement this solution in the project I am working on. I will create a separate question for this because it seems to raise different issues.

cjg
  • 3
  • 2