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.