简体   繁体   中英

Swift: Create array with different custom types

I'm making a registration form app. This lets users create questions and display the created questions in a UITableView. Users can create 2 types of questions, text input(using textfields) and multiple choice(using segmentedcontrol). Here is the class I created to make this happen.

class Question {
var Label: String
var required: Int

// create question
init (Label: String, required: Int) {
    self.Label = Label
    self.required = required

    if (self.required == 0) {
        self.Label = self.Label + " *"
    }
}
}

class textInput: Question {
var placeHolder: String

init (placeHolder: String, Label: String, required: Int) {
    self.placeHolder = placeHolder
    super.init(Label: Label, required: required)
}
}

class multiChoice: Question {
var answers: [String]

init(answers: [String], Label: String, required: Int) {
    self.answers = answers
    super.init(Label: Label, required: required)
}
}

I will need to populate an array with textInput or multiChoice types which will be displayed in the UITableView. In C++ you can use templates to accomplish this arbitrary type issue. Is there a way to do that in Swift, and if so could I get pointers on how to do it with these classes?

First off. Change your Question class as follows:

var required: Bool

init (Label: String, required: Bool) {
    self.Label = Label
    self.required = required

    if self.required {
        self.Label = self.Label + " *"
    }
}

Next, you can use an array of type [Question] to achieve what you're looking for. Then you can do specific actions based on the class using guard or if let structures.

One way to accomplish what you want that is very clean and type safe is to create an enum with associated values for the different types that you will be using. Then you can create an array of enum values and unwrap them using a switch to get at what you want.

class QuestionBase {
    var label: String
    var required: Bool

    // create question
    init (label: String, required: Bool) {
        self.label = label
        self.required = required

        if required {
            self.label = self.label + " *"
        }
    }
}

class TextInputQuestion: QuestionBase {
    var placeHolder: String

    init (placeHolder: String, label: String, required: Bool) {
        self.placeHolder = placeHolder
        super.init(label: label, required: required)
    }
}

class MultiChoiceQuestion: QuestionBase {
    var answers: [String]

    init(answers: [String], label: String, required: Bool) {
        self.answers = answers
        super.init(label: label, required: required)
    }
}

enum Question {
    case TextInput(TextInputQuestion)
    case MultiChoice(MultiChoiceQuestion)
}

let q1 = TextInputQuestion(placeHolder: "placeholder", label: "q1", required: true)
let q2 = MultiChoiceQuestion(answers: ["answer1", "answer2"], label: "q2", required: false)

let questions: [Question] = [.TextInput(q1), .MultiChoice(q2)]

for question in questions {
    switch question {
    case .TextInput(let question):
        print(question.placeHolder)
    case .MultiChoice(let question):
        print(question.answers)
    }
}

enum s are very powerful this way. The array is all of one type: Question . The associated values can be of any type. You could have a TrueFalse case , or even an Essay case .

I rewrote much of your code - it violated a lot of the Swift style guidelines and it made it very hard to read. Type names, like class names, should all be LikeThis (starting with an uppercase letter), while properties should all be in camelCase (starting with a lowercase letter). And I renamed some of the types just to make it more clear what the intentions were. You can take those changes or leave them.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM