I want to display a String in a separate function and just call the function when the user choose the wrong answer, the problem is when I create the function and I try to use it my app crash and is telling me an error about the index is out of range..... any suggestion how can I fix this? or a recommendation to do a better and clean job? Here is my code:
//This is my struct
struct Question {
var Question: String!
var Answers: [String]!
var Answer: Int!
var Img: UIImage!
var Info: String!
}
override func viewDidLoad() {
super.viewDidLoad()
//Here the way I display the questions
questions = [
Question(
Question: "Question #1",
Answers: ["A","B","C","D"],
Answer: 1,
Img: UIImage.self(named: "steve"),
Info: "Steve"
),
]
//Here is my function that I want to create to display the Info:
private function showInformation() {
infoLabel.text = questions[Question].Info
}
Ps: If need more details let me know, by the way my function to create a random question is this
private func pickingRandomQuestion() {
if questions.count > 0 {
questionNumber = random() % questions.count //This make a random pick of Question
questionLabel.text = questions[questionNumber].Question //Converting quesitonLabel into TEXT
answerNumber = questions[questionNumber].Answer
imgDisplay.image = questions[questionNumber].Img
//Im trying to use one of this examples to display but is not working :(
answerA.setTitle(questions[questionNumber].Answers[0], forState: .Normal)
answerB.setTitle(questions[questionNumber].Answers[1], forState: .Normal)
answerC.setTitle(questions[questionNumber].Answers[2], forState: .Normal)
answerD.setTitle(questions[questionNumber].Answers[3], forState: .Normal)
questions.removeAtIndex(questionNumber)
} else {
finishGame.hidden = false
answerA.hidden = true
answerB.hidden = true
answerC.hidden = true
answerD.hidden = true
}
}
You need to store your question's info in a property before you remove the question from the array of questions.
Add a property to your class:
var questionInfo = ""
In pickingRandomQuestion set the value before calling removeAtIndex:
questionInfo = questions[questionNumber].Info
Then use the property value in showInformation:
private function showInformation() {
infoLabel.text = questionInfo
}
Related
I have created a class
class NewTabContainerModal {
var newContainerDate = Date()
var newContainerSelectedFilter : NewAllErrorFIlter = .Yearly
func resetModal () {
newContainerSelectedFilter = .Yearly
newContainerDate = Date()
}
}
I have created an enum to get the values from it
enum NewAllErrorFIlter : String {
case Monthly = "2"
case Yearly = "1"
case Daily = "3"
}
Now in my ViewController class I have created a variable
var newContainerModal: NewTabContainerModal?
And in viewWillAppear I am trying to print the value of the enum like this
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
let newContainerModelData = newContainerModal?.newContainerSelectedFilter
print(newContainerModelData)
}
but it is giving me nil instead of yearly value. I don't understand what I am doing wrong. Please help?
Its because newContainerModal in your Viewcontroller is nil so newContainerModal?.newContainerSelectedFilter also gonna be a nil change it with
var newContainerModal: NewTabContainerModal = NewTabContainerModal()
In addition
let newContainerModelData = newContainerModal.newContainerSelectedFilter
print(newContainerModelData)
will print Yearly. to get that value use newContainerModelData.rawValue
I am in the process of creating an application that will display a list of stocks that a user saves in a tableView. It will also allow the user to add or remove items from their favorites. I need help defining the database structure and setting up for the adding and constant updating of the user's favorite stocks.
I currently have a StockData struct that works with my tableView and a button for adding to the user's list:
struct StockData {
let currentPrice: Double
// meta data
let name: String
let ticker: String
let interval: String
let lastRefreshed: String
let change: Double
}
// In an actual ViewController
#IBAction func addButtonClicked(_ sender: Any) {
print("Add clicked")
// Handle adding the item to the user's list
}
Now as far as my current realm model is concerned, I have:
class User: Object {
#objc dynamic var name = ""
#objc dynamic var id = ""
var stockFavs = List<StockItem>()
}
class StockItem: Object {
#objc dynamic var currentPrice: Double = 0.0
// meta data
#objc dynamic var name = ""
#objc dynamic var ticker = ""
#objc dynamic var interval = ""
#objc dynamic var lastRefreshed = ""
#objc dynamic var change: Double = 0.0
}
// Setting up the user and creating test values
let newUser = User()
newUser.name = "John Smith"
newUser.id = "coolId123"
var stockArr = List<StockItem>()
for i in 0..<12 {
let item = StockItem()
item.name = "Microsoft Corporation"
item.change = -3.55
item.currentPrice = 123.45
item.interval = "1day"
item.lastRefreshed = "Now"
item.ticker = "MSFT"
stockArr.append(item)
}
newUser.stockFavs = stockArr
try! realm.write {
realm.add(newUser)
}
So far, I have been able to create a user object for the current user of the device and add test values, but I am unsure how to implement constant realm updating (the method would have self.tableView.reloadData(), but apart from that, I'm clueless) in conjunction with the ability to add StockItem's to the user's array.
Any help would be much appreciated!
You use a function for every time you want to add to the database.
let button = UIButton(frame: CGRect(x: 0, y: 0, width: 100, height: 100)
button.addTarget(self, action: #selector(add), for: .touchUpInside)
func add() {
let currentData = [MyFakeData1, MyFakeData2, etc.]
try! realm.write {
realm.add(currentData)
}
// You need to get the updates in the database
// You could have an array in your model that you update and then append all
// the new items to it and only do database lookups when you restart the
// device
update()
}
func update() {
let realm = try! Realm()
var newArray = realm.objects(StockItem.self)
myViewController.modelArray = newArray
table.reloadData()
}
I am trying to set up questions with a text field for answers. Only after the exact answer has been entered can the next question be shown. I'm getting an error code with "if answerField == answers[currentQuestionIndex]" I believe I need to have allowances for what can be entered as answers. I'm stuck and could use some help in the right direction. thank you
#IBAction func answerField(sender: AnyObject) {
for index in 1...5 {
if answerField == answers[currentQuestionIndex] {
++self.currentQuestionIndex
if self.currentQuestionIndex == self.questions.count {
self.currentQuestionIndex = 0
}
}
}
}
let questions: [String] = ["From what is cognac made?", "What is 7+7?", "What is the capital of Vermont?"]
let answers: [String] = ["Grapes", "14", "Montpelier"]
override func viewDidLoad() {
super.viewDidLoad()
currentQuestion.text = questions[currentQuestionIndex]
}
answerField as you've shown it here is not a UITextField; it is a function. That is what the error is telling you: A function that takes AnyObject as a parameter and returns nothing ((AnyObject)->()) can't be compared to a String.
I think perhaps what you wanted to do was create an outlet (not an action) for your answer field:
#IBOutlet weak var answerField: UITextField! // Make sure you actually hook this up to your text field in the storyboard.
Then, listen for changes to the content of the text field:
override func viewDidLoad()
{
super.viewDidLoad()
answerField.addTarget(
self,
action: #selector(answerChanged(_:)),
forControlEvents: .EditingChanged)
currentQuestion.text = questions[currentQuestionIndex]
}
And then handle changes to your answer field text:
func answerChanged(sender: AnyObject)
{
if (answerField.text ?? "") == answers[currentQuestionIndex]
{
currentQuestionIndex = currentQuestionIndex + 1 < questions.count ? currentQuestionIndex + 1 : 0
currentQuestion.text = questions[currentQuestionIndex]
}
}
Or something along those lines.
If you answerField variable is UIText field then you need to use its text. The is an optional property so you also need to unwrap it
if (answerField.text ?? "") == answers[currentQuestionIndex]
From error code mentioned seems like you don't have variable answerField and you are trying to compare function itself to String, that doesn't make any sense
I recently started learning Swift which is my first attempt to learning how to program and I started my first app. I used several tutorials and so far I could solve every problem through research. Now I am stuck.
I want to create an app that can pick a random cocktail for me out of an array (cocktails) based on filters. To do so, I created 21 filters (cocktail.filter({!$o.orangeJuice}) for example. This takes all cocktails out of the array using orange juice.).
Creating the UI I added 21 UISwitches to toggle whether a filter has to be applied or not.
My randomize button works and there is a random cocktail name displayed but I can't get those UISwitches to work.
See my code:
var cocktailNoOrangeJuice = cocktails.filter({!$0.orangeJuice})
var cocktailNoLemonJuice = cocktails.filter({!$0.lemonJuice})
var cocktailNoAppleJuice = cocktails.filter({!$0.appleJuice})
var cocktailNoMaraJuice = cocktails.filter({!$0.maraJuice})
var cocktailNoLimeJuice = cocktails.filter({!$0.limeJuice})
var cocktailNoBananaJuice = cocktails.filter({!$0.bananaJuice})
var cocktailNoPeachJuice = cocktails.filter({!$0.peachJuice})
var cocktailNoCherryJuice = cocktails.filter({!$0.cherryJuice})
var cocktailNoJohanJuice = cocktails.filter({!$0.johanJuice})
var cocktailNoMangoJuice = cocktails.filter({!$0.mangoJuice})
var cocktailNoGrapefJuice = cocktails.filter({!$0.grapefJuice})
var cocktailNoTomatoJuice = cocktails.filter({!$0.tomatoJuice})
var cocktailNoCranbJuice = cocktails.filter({!$0.cranbJuice})
var cocktailNoBloodJuice = cocktails.filter({!$0.bloodJuice})
var cocktailNoPineapJuice = cocktails.filter({!$0.pineapJuice})
var cocktailNoCola = cocktails.filter({!$0.cola})
var cocktailNoSprite = cocktails.filter({!$0.sprite})
var cocktailNoBitter = cocktails.filter({!$0.bitter})
var cocktailNoTonic = cocktails.filter({!$0.tonic})
var cocktailNoGinger = cocktails.filter({!$0.ginger})
var cocktailNoAlc = cocktails.filter({!$0.noalc})
//this is a new array currently with the "noalc"-filter applied
var cocktailfiltered = cocktails.filter({!$0.noalc})
class ViewController: UIViewController {
// this is one of the UISwitches
#IBOutlet weak var lemon: UISwitch!
// The label for Cocktail output and the random button
#IBOutlet weak var ergebnis: UILabel!
#IBAction func random(sender: AnyObject) {
let randomIndex = Int(arc4random_uniform(UInt32(cocktailfiltered.count)))
ergebnis.text = (cocktailfiltered[randomIndex].name)
}
}
Please forgive me if this too silly. I found out how to pick up the state of a UISwitch (e.g lemon.on ...) but cannot use this information to apply a filter.
Any help is highly appreciated. Though I first hoped to be able to solve this on my own now it gets frustrating.
Notice that the cocktails are defined as members of a class and every ingredient such as orange juice throws a bool. Thus the filters are manually working. But not in the UI.
Edit: So this is the version right now. In my opinion it looks far better thanks to #vadian but causes my app to crash.
class ViewController: UIViewController {
let keys = ["lemonJuice", "limeJuice", "bananaJuice", "pineapJuice", "maraJuice", "mangoJuice", "orangeJuice", "appleJuice", "peachJuice", "bloodJuice", "grapefJuice", "tomatoJuice", "cranbJuice", "cherryJuice", "johanJuice", "cola", "sprite", "bitter", "tonic", "ginger", "noalc"]
var states = [true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true]
#IBAction func changeState(sender: UISwitch) {
let index = sender.tag
states[index] = sender.on}
#IBOutlet weak var ergebnis: UILabel!
#IBAction func random(sender: AnyObject) {
var conditions = [String]()
for (index, state) in states.enumerate() {
if state {
conditions.append("(\(keys[index]) == TRUE)")
}
}
let format = conditions.joinWithSeparator(" AND ")
let predicate = NSPredicate(format:format)
let filtered = (cocktails as NSArray).filteredArrayUsingPredicate(predicate)
let randomIndex = Int(arc4random_uniform(UInt32(filtered.count)))
ergebnis.text = (filtered[randomIndex].name)
}
}
Suggestion:
Create two arrays, one for the names/keys of the Bool properties in your custom class
let keys = ["orangeJuice", "lemonJuice" ... ]
and one for the states of the corresponding switches
var states = [false, false, ...]
Assign tags to the UISwitches starting with zero in order of the keys array.
Create a change state IBAction and assign the action to all UISwitches
#IBAction func changeState(sender: UISwitch) {
let index = sender.tag
states[index] = sender.on
}
in the random function create an NSPredicate programmatically by a repeat loop to get all true values of the states array and the corresponding key of the keys array. Then filter the cocktail array by that predicate and get the random cocktail.
PS: For a good user experience get the filtered cocktails in the changeState function and inform the user in case no cocktail matches the chosen ingredients.
Update:
An example to create the predicate
var conditions = [String]()
for (index, state) in states.enumerate() {
if state {
conditions.append("(\(keys[index]) == TRUE)")
}
}
let format = conditions.joinWithSeparator(" AND ")
let predicate = NSPredicate(format:format)
It's rather easy to create a simple TableView with one row type.
You just set
tableView.setNumberOfRows(yourArray.count, withRowType: "yourowtype")
and then add a for loop to fill up your uilabel or whatever you have with data from the array.
When it comes to multiple row types, it's not so clear. I'm aware you have to set
tableView.setRowTypes(yourRowTypesArray)
but i don't understand the rest.
In iOS you have a very clear and straightforward indexPath.row solution in the cellForRowAtIndexPath, where you can say - Okay, i want this array to fill those indexPaths, the other array should fill those e.t.c. with simple IF conditional.
In WatchKit, however, there is no such thing as indexPath.row and it's not clear to me how you can assign specific row numbers for a specific array ? And why should you remove setNumberOfRows (as i've seen in the examples all over the net) in a multiple row type solution?
I've browsed the net heavily regarding the issue and i haven't been able to find a decent workable solution. Just tricks and workarounds.
Thank you.
UPDATE: Adding codes
My arrays
var questionsList = [["[What is the color of?]"],["Which city is the capital of Great Britain", "additional info"],["Some question"]]
var answersList1 = [["Blue"],["London"],["some answer 1"]]
var answersList2 = [["Grey"],["Liverpool"],["some answer 2"]]
The loadTable function
private func loadTable(){
tableView.setRowTypes(rowTypes)
for i in 0 ..< questionsList[0].count {
let rowController = tableView.rowControllerAtIndex(i) as! TableViewRowController
rowController.lblQuestion.setText(questionsList[0][i])
}
let rowController1 = tableView.rowControllerAtIndex(answersList1[0].count) as! AnswerRowController1
rowController1.button1.setTitle(answersList1[0][0])
let rowController2 = tableView.rowControllerAtIndex(answersList2[0].count+1) as! AnswerRowController2
rowController2.button2.setTitle(answersList2[0][0])
}
I would rather suggest you to refine your model. It looks really difficult to understand. Refactor it into class or struct to make it easy to understand.
Here is my approach to refactor it a bit and create a sort of thing that you wanted,
let QuestionRowIdentifier = "QuestionRowIdentifier"
let AnswerRowIdentifier = "AnswerRowIdentifier"
let QuestionSeparatorRowIdentifier = "QuestionSeparatorIdentifier"
protocol QuestionAnswerRowTypes {
var titleLabel: WKInterfaceLabel! { get set }
}
class QuestionRowController: NSObject, QuestionAnswerRowTypes {
#IBOutlet var titleLabel: WKInterfaceLabel!
}
class AnswerRowController: NSObject, QuestionAnswerRowTypes {
#IBOutlet var titleLabel: WKInterfaceLabel!
}
struct Question {
let title: String
let additionalInfo: String?
let answers: [String]
}
let questions = [
Question(title: "What is the color of?", additionalInfo: nil, answers: [
"Blue",
"Gray"
]),
Question(title: "Which city is the capital of Great Britain?", additionalInfo: "additional info", answers: [
"London",
"Liverpool"
]),
Question(title: "Some question?", additionalInfo: nil, answers: [
"some answer 1",
"some answer 2"
])
]
class InterfaceController: WKInterfaceController {
#IBOutlet private var tableView: WKInterfaceTable!
var names = ["Alexander", "Ferdinand", "Jack", "Samuel", "Thompson", "Tony"]
override func awakeWithContext(context: AnyObject?) {
super.awakeWithContext(context)
let rowTypes = getRowTypes()
tableView.setRowTypes(rowTypes)
for i in 0 ..< rowTypes.count {
if let rowController = tableView.rowControllerAtIndex(i) as? QuestionAnswerRowTypes {
rowController.titleLabel.setText(textAtIndex(i)!)
}
}
}
func getRowTypes() -> [String] {
return questions.flatMap { question in
return [
[QuestionRowIdentifier],
Array(count: question.answers.count, repeatedValue: AnswerRowIdentifier),
[QuestionSeparatorRowIdentifier]
].flatMap { $0 }
}
}
func textAtIndex(index: Int) -> String? {
let titles = questions.flatMap { question in
return
[
[Optional.Some(question.title)],
question.answers.map(Optional.Some),
[Optional.None],
]
}.flatMap( { $0 })
return titles[index]
}
}
And here is the end result,