How to determine a struct's return value based on UI Objects

Viewed 57

I currently have a struct in which my ViewController references to return a random value from a group of arrays (aList, bList, cList, & dList). I ideally would like to be have aList always enabled while being able to toggle bList, cList, & dList on/off.

I have all this in a struct (shown below) but I'm very new to Swift and am learning that structs are "value types" while the ViewController is a "reference type" and apparently UI objects can only be referenced from reference types?

import GameKit
import Foundation

struct PromptProvider {


    var aListIndex = 0
    var bListIndex = 0
    var cListIndex = 0
    var dListIndex = 0

    var includeB = false
    var includeC = false
    var includeD = false


    var aList = [
        “A1”,
        “A2”,
        “A3”,
        “A4”]

    var bList = [
        “B1”,
        “B2”,
        “B3”,
        “B4”]

    var cList = [
        “C1”,
        “C2”,
        “C3”,
        “C4”]

    var dList = [
        “D1”,
        “D2”,
        “D3”,
        “D4”]


    init() {
        self.restart()
    }



    mutating func restart() {
        if includeB == true {self.aList.append(contentsOf: bList)}
        if includeC == true {self.aList.append(contentsOf: cList)}
        if includeD == true {self.aList.append(contentsOf: dList)}
        self.aList.shuffle()
        self.aListIndex = 0
    }


    mutating func randomPrompt() -> String {

        if aListIndex == aList.count {
            return "Out of String Values"
        }
        else {
            defer {aListIndex += 1}
            return aList[aListIndex]
        }
    }


}

I think I'm treating the struct as a reference type here but am unable to connect a UI object to the structs code.

Any help/guidance on how to pivot my strategy with this would be greatly appreciated. Thank you

1 Answers

As long as you have a single instance of PromptProvider you can make changes to that instance at will. If you need multiple references to a PromptProvider then you will need to make PromptProvider a class.

I mentioned that you had a bug in your restart method. You were appending data to your aList array without clearing out the previous appended data. What you need is a master list to contain your aList as well as the contents of your other lists so you can reset it as needed.

If I were you, I'd implement your PromptProvider struct like this:

struct PromptProvider {

    let aList = [
        "A1",
        "A2",
        "A3",
        "A4"]

    let bList = [
        "B1",
        "B2",
        "B3",
        "B4"]

    let cList = [
        "C1",
        "C2",
        "C3",
        "C4"]

    let dList = [
        "D1",
        "D2",
        "D3",
        "D4"]

    var includeB = false {
        didSet { restart() }
    }

    var includeC = false {
        didSet { restart() }
    }

    var includeD = false {
        didSet { restart() }
    }

    var masterList: [String] = []

    init() {
        self.restart()
    }

    mutating func restart() {
        masterList.removeAll()
        masterList.append(contentsOf: aList)
        if includeB == true {masterList.append(contentsOf: bList)}
        if includeC == true {masterList.append(contentsOf: cList)}
        if includeD == true {masterList.append(contentsOf: dList)}
        masterList.shuffle()
    }

    mutating func randomPrompt() -> String? {
        return masterList.popLast()
    }
}

And then in your view controller you can declare and use your PromptProvider like so:

class ViewController: UIViewController {

    var promptProvider = PromptProvider()

    @IBAction func onPrintRandomPrompt(_ sender: UIButton) {
        if let prompt = promptProvider.randomPrompt() {
            print(prompt)
        } else {
            print("Out of String Values")
            promptProvider.restart()
        }
    }
}

If you want to change the contents of the provider all you have to do is toggle its flags and that will reset the contents of the master list.

extension ViewController {

    @IBAction func onIncludeB(_ sender: UIButton) {
        promptProvider.includeB.toggle()
        sender.setTitleColor(promptProvider.includeB ? .green : .red, for: .normal)
    }

    @IBAction func onIncludeC(_ sender: UIButton) {
        promptProvider.includeC.toggle()
        sender.setTitleColor(promptProvider.includeC ? .green : .red, for: .normal)
    }

    @IBAction func onIncludeD(_ sender: UIButton) {
        promptProvider.includeD.toggle()
        sender.setTitleColor(promptProvider.includeD ? .green : .red, for: .normal)
    }
}
Related