IOS Updating button title and updating array with button value? - ios

I am new to IOS Development and am implementing IOS QUIZ App.
How to update question and answers in QUIZ app.
Please check below my code this is how I am displaying.
#IBOutlet weak var prevBtn: UIButton!
#IBOutlet weak var nxtBtn: UIButton!
#IBOutlet weak var qstnlbl: UILabel!
#IBOutlet weak var answerABtn: UIButton!
#IBOutlet weak var answerBBtn: UIButton!
#IBOutlet weak var answerCBtn: UIButton!
#IBOutlet weak var answerDBtn: UIButton!
let questions = ["How many days are there in 1 year?", "Favorite color?", "Where was I born?"]
let answers = [["360", "365", "384", "377"], ["blue", "black", "green", "orange"], ["Tokyo", "New York", "Tennessee", "rajahmundry"]]
//Variables
var currentQuestion = 0
var rightAnswerPlacement:UInt32 = 0
var points = 0;
//Label
#IBOutlet weak var lbl: UILabel!
//Button
#IBAction func action(_ sender: AnyObject)
{
if (sender.tag == Int(rightAnswerPlacement))
{
print ("RIGHT!")
points += 1
}
else
{
print ("WRONG!!!!!!")
}
if (currentQuestion != questions.count)
{
newQuestion()
}
}
#IBAction func preAction(_ sender: AnyObject)
{
if (currentQuestion != questions.count)
{
newQuestion()
}
currentQuestion = currentQuestion - 1
}
#IBAction func nxtaction(_ sender: AnyObject)
{
if (currentQuestion != questions.count)
{
newQuestion()
}
currentQuestion = currentQuestion + 1
}
override func viewDidAppear(_ animated: Bool)
{
newQuestion()
}
//Function that displays new question
func newQuestion()
{
qstnlbl.text = questions[currentQuestion]
rightAnswerPlacement = arc4random_uniform(3)+1
//Create a button
var button:UIButton = UIButton()
var x = 1
for i in 1...4
{
//Create a button
button = view.viewWithTag(i) as! UIButton
button.setTitle(answers[currentQuestion][x], for: .normal)
x = 2
}
currentQuestion += 1
}
based on user selection answers has be to added to answerArray.
For Ex: if user selects in first question in answerABtn answer option "A " answerArray has to update with "A" value.
user can able to update answer
for Ex: user select 1st question answer option "b" answerArray has to update with "b" value.
please help me out to make this quiz app.
quiz app ui
enter image description here

There are quite a few things you should be doing differently, but to get you on your way...
You will want to create a answerArray variable to hold the user-selected answers. Inside your action func, you are already tracking which button was tapped, so append the button's title to your answer array at the same point.
Your current previous and next actions don't make any sense, because you are not tracking the question count correctly, and you are picking a random "correct" answer each time.
Here is your code, modified for:
better question count incrementing
tracking user selected answers in answerArray
clearing the screen when the quiz is complete
Note: this is just example code... this should not be considered "everything fixed" -- but it should help you with this step. Review the comments I've added to your code.
class QuizViewController: UIViewController {
#IBOutlet weak var prevBtn: UIButton!
#IBOutlet weak var nxtBtn: UIButton!
#IBOutlet weak var qstnlbl: UILabel!
#IBOutlet weak var answerABtn: UIButton!
#IBOutlet weak var answerBBtn: UIButton!
#IBOutlet weak var answerCBtn: UIButton!
#IBOutlet weak var answerDBtn: UIButton!
let questions = ["How many days are there in 1 year?", "Favorite color?", "Where was I born?"]
let answers = [["360", "365", "384", "377"], ["blue", "black", "green", "orange"], ["Tokyo", "New York", "Tennessee", "rajahmundry"]]
//Variables
var currentQuestion = 0
var rightAnswerPlacement:UInt32 = 0
var points = 0;
// array to hold answers
var answerArray: [String] = [String]()
//Label
#IBOutlet weak var lbl: UILabel!
//Button
#IBAction func action(_ sender: AnyObject)
{
// make sure this came from a button, and get the button title
guard let btn = sender as? UIButton,
let btnTitle = btn.currentTitle else { return }
if (btn.tag == Int(rightAnswerPlacement))
{
print ("RIGHT!")
points += 1
}
else
{
print ("WRONG!!!!!!")
}
// append the selected answer to the answerArray
answerArray.append(btnTitle)
// increment question counter
currentQuestion += 1
// if there are more questions
if (currentQuestion < questions.count)
{
newQuestion()
}
else
{
quizComplete()
}
}
func quizComplete() -> Void {
[answerABtn, answerBBtn, answerCBtn, answerDBtn].forEach {
$0?.isHidden = true
}
qstnlbl.text = "Your score: \(points)"
}
// these two funcs do not make any sense as written
/*
#IBAction func preAction(_ sender: AnyObject)
{
if (currentQuestion != questions.count)
{
newQuestion()
}
currentQuestion = currentQuestion - 1
}
#IBAction func nxtaction(_ sender: AnyObject)
{
if (currentQuestion != questions.count)
{
newQuestion()
}
currentQuestion = currentQuestion + 1
}
*/
override func viewDidAppear(_ animated: Bool)
{
newQuestion()
}
//Function that displays new question
func newQuestion()
{
qstnlbl.text = questions[currentQuestion]
rightAnswerPlacement = arc4random_uniform(3)+1
for i in 1...4
{
// get a reference to a button
let button = view.viewWithTag(i) as! UIButton
button.setTitle(answers[currentQuestion][i-1], for: .normal)
}
// don't increment question count here
// increment it AFTER user answers the question (in button tap action)
//currentQuestion += 1
}
}

here you go:
import UIKit
class ViewController: UIViewController {
var emptyArray : [String] = []
override func viewDidLoad() {
super.viewDidLoad()
self.view.backgroundColor = .red
}
#objc func buttonAction(sender: UIButton!) {
emptyArray.append("A")
print(emptyArray)
}
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
let button = UIButton()
button.frame = CGRect(x: self.view.frame.size.width - 300, y: 200, width: 100, height: 100)
button.backgroundColor = UIColor.blue
button.setTitle("Name your Button ", for: .normal)
button.addTarget(self, action: #selector(buttonAction), for: .touchUpInside)
self.view.addSubview(button)
}
}
when you press the buttom over and over, the output to debug window is this
["A"]
["A", "A"]
["A", "A", "A"]
["A", "A", "A", "A"]

Related

UIImageView Array iOS13

I am trying with learning Swift and got stuck on an issue here.
import UIKit
class ViewController: UIViewController {
#IBOutlet weak var diceImageView1: UIImageView!
#IBOutlet weak var diceImageView2: UIImageView!
var leftDiceNumber=1
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
diceImageView1.image = UIImage(imageLiteralResourceName: "DiceSix")
// change transparency with diceImageView1.alpha=0.7
}
#IBAction func rollButtonPressed(_ sender: UIButton) {
print("button pressed")
diceImageView1 = [ UIImageView(imageLiteralResourceName: "DiceOne"),UIImageView(imageLiteralResourceName: "DiceTwo"),UIImageView(imageLiteralResourceName: "DiceThree"),UIImageView(imageLiteralResourceName: "DiceFour"),UIImageView(imageLiteralResourceName: "DiceFive"),UIImageView(imageLiteralResourceName: "DiceSix")],[leftDiceNumber]
leftDiceNumber=leftDiceNumber+1
}
}
But all I get is the error messages on the IBAction:
1.Argument passed to call that takes no arguments
2.Cannot assign value of type '[UIImageView]' to type 'UIImageView'
3.Consecutive statements on a line must be separated by ';'
4.Expected expression
What's the difference between UIImageView and UIImage ? When they should be used?
Many Thanks in advance !
You want to change the .image property to change the image.
To "cycle through" the dice, you could do this:
class DiceViewController: UIViewController {
#IBOutlet weak var diceImageView1: UIImageView!
#IBOutlet weak var diceImageView2: UIImageView!
let diceNames: [String] = [
"DiceOne", "DiceTwo", "DiceThree", "DiceFour", "DiceFive", "DiceSix"
]
var leftDiceNumber = 0
override func viewDidLoad() {
super.viewDidLoad()
diceImageView1.image = UIImage(named: diceNames[leftDiceNumber % 6])
}
#IBAction func rollButtonPressed(_ sender: UIButton) {
print("button pressed")
// increment the index
leftDiceNumber += 1
// udpate the image view
diceImageView1.image = UIImage(named: diceNames[leftDiceNumber % 6])
}
}
I'm guessing your goal is to "randomly roll" the dice, so take a look at this slightly different class:
class DiceViewController: UIViewController {
#IBOutlet weak var diceImageView1: UIImageView!
#IBOutlet weak var diceImageView2: UIImageView!
let diceNames: [String] = [
"DiceOne", "DiceTwo", "DiceThree", "DiceFour", "DiceFive", "DiceSix"
]
override func viewDidLoad() {
super.viewDidLoad()
// start with both dice at One
diceImageView1.image = UIImage(named: diceNames[0])
diceImageView2.image = UIImage(named: diceNames[0])
}
#IBAction func rollButtonPressed(_ sender: UIButton) {
print("button pressed")
// arrays are Zero-based, so get a random Int
// from 0 to 5
//let l = Int.random(in: 0...5)
//let r = Int.random(in: 0...5)
//diceImageView1.image = UIImage(named: diceNames[l])
//diceImageView2.image = UIImage(named: diceNames[r])
// more "modern Swifty" method
if let nm = diceNames.randomElement() {
diceImageView1.image = UIImage(named: nm)
}
if let nm = diceNames.randomElement() {
diceImageView2.image = UIImage(named: nm)
}
}
}

Swift NSTiimer not following specified Interval

I am trying to create a quiz app which has a timer for each question when the timer expires (i.e. 10 seconds and I want Timer to have an interval of 1 sec) it resets it self and next question is fetched and Timer again restart from 10... But my issue is the timer doesn't follow a fixed interval when first question is loaded it shows interval of 2 ... i.e. 10,8,6 .. and then for second question it makes jump for 3 secs interval and similarly the interval increases.
import UIKit
class ViewController: UIViewController {
let allQuestions = QuestionsBundle()
var pickedAnswer : Int = 0
var questionCounter = 0
var score : Int = 0
var timer: Timer!
#IBOutlet weak var questionLabel: UILabel!
#IBOutlet weak var countDownLabel: UILabel!
#IBOutlet weak var ansLbl1: UILabel!
#IBOutlet weak var ansLbl2: UILabel!
#IBOutlet weak var ansLbl3: UILabel!
#IBOutlet weak var ansLbl4: UILabel!
#IBOutlet weak var checkBox1: CheckBox!
#IBOutlet weak var checkBox2: CheckBox!
#IBOutlet weak var checkBox3: CheckBox!
#IBOutlet weak var checkBox4: CheckBox!
var checkBoxlist : [CheckBox] = []
#IBAction func correct_Answer_Checbox_Btn(_ sender: AnyObject) {
//print("\(sender.tag) <==> \(String(describing: question?.correctAnswer))")
updateCheckBoxes(sender: sender)
if sender.tag == question?.correctAnswer{
question?.isAnswerCorrect = true
question?.selectedAnswer = sender.tag
//score = score + 1
}
else {
question?.isAnswerCorrect = false
}
}
func updateCheckBoxes(sender: AnyObject){
for checkBoxItem in checkBoxlist{
if checkBoxItem.tag != sender.tag {
checkBoxItem.isChecked = false
}
}
}
#IBOutlet weak var nextButton: UIButton!
#IBAction func nextBtnClicked(_ sender: AnyObject) {
do{
try handleNextQuestion()
}
catch{
moveToResultView()
}
}
func handleNextQuestion() throws {
nextQuestion()
if questionCounter == allQuestions.list.count-1{
finishButton.isHidden = false
nextButton.isHidden = true
//scoreLbl.text = "\(score)"
}
}
var question : Question?
var countTime = 10.0
override func viewDidLoad() {
super.viewDidLoad()
finishButton?.isHidden = true
checkBoxlist = fetchCheckBoxList()
question = fetchQuestion()
setQuizView(question: question!)
// Do any additional setup after loading the view, typically from a nib.
}
// set all questions in a function
#objc func update() {
if(countTime > 0) {
countTime = countTime - 1
self.countDownLabel.text = String(countTime)
}else{
timer.invalidate()
countTime = 10.0
do{
try handleNextQuestion()
}
catch{
moveToResultView()
}
}
}
func startTimer() {
timer = Timer.scheduledTimer(timeInterval: 1.0, target: self, selector: #selector(ViewController.update), userInfo: nil, repeats: true)
}
func setQuizView(question:Question) {
self.countDownLabel.text = "10"
startTimer()
questionLabel.text = question.questionText
ansLbl1.text = question.answer1
ansLbl2.text = question.answer2
ansLbl3.text = question.answer3
ansLbl4.text = question.answer4
if question.selectedAnswer == Constants.DEFAULT_ANSWER {
for checkBoxItem in checkBoxlist{
checkBoxItem.isChecked = false
}
}
}
#IBOutlet weak var finishButton: UIButton!
// prepare segue
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == resultScreenIdentifier{
let vc = segue.destination as! ResultViewController
vc.data = sender as! String
}
}
let resultScreenIdentifier = "resultScreenSegue"
func moveToResultView(){
performSegue(withIdentifier: resultScreenIdentifier, sender: score)
}
#IBAction func finishButtonClicked(_ sender: UIButton) {
//perform segue
let score = "\(calculateScore())"
moveToResultView()
}
// calculate the score of quiz using loop
func calculateScore()->Int{
var numOfCorrectAnswers = 0
for question in allQuestions.list{
if question.isAnswerCorrect {
numOfCorrectAnswers = numOfCorrectAnswers + 1
//print(numOfCorrectAnswers)
}
}
return numOfCorrectAnswers
}
func nextQuestion(){
showResultView(isCorrect: (question?.isAnswerCorrect)!)
questionCounter = questionCounter + 1
question = fetchQuestion()
setQuizView(question: question!)
}
func fetchQuestion() -> Question{
return allQuestions.list[questionCounter]
}
func fetchCheckBoxList() -> [CheckBox]{
let arr : [CheckBox] = [checkBox1,checkBox2,checkBox3,checkBox4]
return arr
}
}
Timers are not particularly accurate. They can suffer from significant jitter.
A better approach is to create a Date that represents the expiration time (ie Date(timeIntervalSinceNow:10) and then run a Timer with a much shorter interval (I would suggest around 0.1 second). You can then calculate the time remaining based on the target Date and check if the target date is in the past.

Is it possible to toss data to another view controller?

I just Make timer that can use in life. just like image that I push in here, if I go back to main ViewController then I wanna the number that I input in set view controller are tossed to viewController so when I go back to main ViewController and press restart then that number gonna be in text of CountTimeLabel.. but I really don't know how to toss data that I input in another view controller to root viewController... pleas help me.. if I write code like ViewController().variableName = 30 in setViewController, that dose not make things well..(I already know about prepare function but that is not what I am finding..because this is happen when I go back to ViewController(RootViewController)) I will put my code in below..
is it possible to toss data to another view controller from other view controller?
import UIKit
class ViewController: UIViewController{
#IBOutlet var AllTileLabel: UILabel!
#IBOutlet var SumTimeLabel: UILabel!
#IBOutlet var CountTimeLabel: UILabel!
#IBOutlet var StartButton: UIButton!
#IBOutlet var StopButton: UIButton!
#IBOutlet var ResetButton: UIButton!
var timeTrigger = true
var realTime = Timer()
var second : Int = 3000
var sum : Int = 14400
var allTime : Int = 14400
var IntSecond : Int = 0
var ifReset = false
override func viewDidLoad() {
StartButton.layer.cornerRadius = 10
StopButton.layer.cornerRadius = 10
ResetButton.layer.cornerRadius = 10
super.viewDidLoad()
// Do any additional setup after loading the view.
}
#IBAction func StartButtonAction(_ sender: UIButton) {
if timeTrigger { checkTimeTrigger() }
print("Start")
}
#IBAction func StopButtonAction(_ sender: UIButton) {
endGame()
}
#IBAction func ResetButtonAction(_ sender: UIButton) {
print(second)
getTimeData()
//second = 3000
//CountTimeLabel.text = "0:50:00"
CountTimeLabel.text = printTime(temp: second)
ifReset = true
}
#IBAction func Reset(_ sender: UIButton) {
endGame()
timeTrigger = true
realTime = Timer()
second = 3000
sum = 14400
allTime = 14400
IntSecond = 0
ifReset = false
AllTileLabel.text = "8:00:00"
SumTimeLabel.text = "0:0:0"
CountTimeLabel.text = "0:50:00"
}
#objc func updateCounter(){
// if String(format: "%.2f",second) == "0.00"{
if second < 1 {
endGame()
CountTimeLabel.text = "종료"
} else {
second = second - 1
sum = sum + 1
allTime = allTime - 1
AllTileLabel.text = printTime(temp: allTime)
SumTimeLabel.text = printTime(temp: sum)
CountTimeLabel.text = printTime(temp: second)
print("update")
}
}
func checkTimeTrigger() {
realTime = Timer.scheduledTimer(timeInterval: 1, target: self, selector: #selector(updateCounter), userInfo: nil, repeats: true)
timeTrigger = false
}
func endGame() {
realTime.invalidate()
timeTrigger = true
}
func printTime(temp : Int) -> String
{
let S = temp%60
let H = temp/3600
let M = temp/60 - H*60
let returnString = String(H) + ":" + String(M) + ":" + String(S)
return returnString
}
func getTimeData() {
second = 20
sum = SetViewController().real.sum
allTime = SetViewController().real.allTime
print(second)
}
}
import UIKit
class SetViewController: UIViewController {
#IBOutlet var View1: UIView!
#IBOutlet var View2: UIView!
#IBOutlet var InputView1: UIView!
#IBOutlet var InputView2: UIView!
#IBOutlet var SetButton: UIButton!
#IBOutlet var H1TextField: UITextField!
#IBOutlet var M1TextField: UITextField!
#IBOutlet var H2TextField: UITextField!
#IBOutlet var M2TextField: UITextField!
override func viewDidLoad() {
super.viewDidLoad()
H1TextField.keyboardType = .numberPad
M1TextField.keyboardType = .numberPad
H2TextField.keyboardType = .numberPad
M2TextField.keyboardType = .numberPad
View1.layer.cornerRadius = 14
View2.layer.cornerRadius = 14
InputView1.layer.cornerRadius = 10
InputView2.layer.cornerRadius = 10
SetButton.layer.cornerRadius = 10
// Do any additional setup after loading the view.
}
#IBAction func SetButton(_ sender: UIButton) {
self.dismiss(animated: true, completion: nil)
}
/*
// MARK: - Navigation
// In a storyboard-based application, you will often want to do a little preparation before navigation
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
// Get the new view controller using segue.destination.
// Pass the selected object to the new view controller.
}
*/
}
enter image description here
If you're a hobbyist programmer and you just want to "get it done", simply use a static.
Let's say Bottom: UIViewController is the "main", root, view controller at the absolute "base" of your app. no matter what happens "Bottom" is always there.
Say Timer: UIViewController is (any) other view controller you put on top for some reason.
In Bottom, do this
class Bottom: UIViewController, etc ... {
static weak var current: Bottom? = nil
override func viewDidLoad() {
super.viewDidLoad()
Bottom.current = self
}
func testing() {
print("it works, WTH")
}
Note that in ViewDidLoad, you simply set it.
Next, say you are in Timer, try this:
class Timer: UIViewController, etc ... {
func someFunction() {
Bottom.current.testing() // it's that easy
}
It's that easy.
Note there is a huge amount of confusion about using statics, singletons, and similar approaches in iPhone programming.
(Just for example, many engineers will say "avoid singletons!" This is remarkably confused because in iOS engineering, almost everything is a singleton (notably the app itself (!!!!!), the screen, the GPS, etc etc.)
In any event, as a beginner hobbyist, learn how to use statics (it's simple .. Bottom.current. ... as above), and eventually you can learn about the pros and cons of such things.

Update CoreData Value with UISwitch in UITableViewCell

Just learning so I am sure there are much better ways to code what I have so far. Anyways, I have a simple task list that is saved to core data. You can segue to another VC where you can edit or create new task. I wanted to be able to put a uiswitch in the custom cell that would allow you to set the task as complete and then reload the tableview. I have searched all over and found this Select UITableView's row when tapping on its UISwitch in Swift but can't seem to translate a solution. Any help would be great.
enter image description here
I am not sure if I am supposed to code the save within the custom cell or just or pass delegate.
Here is my custom cell
protocol SettingCellDelegate : class {
func didChangeSwitchState(sender: TaskCell, isOn: Bool)
}
class TaskCell: UITableViewCell {
var delegate: SettingCellDelegate!
#IBOutlet weak var taskImage: UIImageView!
#IBOutlet weak var arrowImage: UIImageView!
#IBOutlet weak var dueDateLabel: UILabel!
#IBOutlet weak var dueDateValue: UILabel!
#IBOutlet weak var dueTimeLabel: UILabel!
#IBOutlet weak var dueTimeValue: UILabel!
#IBOutlet var taskCellStatus: UITextField!
#IBOutlet var taskCellSwitchDisplay: UISwitch!
#IBAction func taskCellSwitchAction(sender: AnyObject) {
if (taskCellSwitchDisplay.on) {
taskCellStatus.text = "Completed"
} else {
taskCellStatus.text = "Active"
}
}
#IBOutlet weak var taskNameValue: UILabel!
override func awakeFromNib() {
super.awakeFromNib()
delegate = self
}
override func setSelected(selected: Bool, animated: Bool) {
super.setSelected(selected, animated: animated)
taskCellSwitchDisplay.addTarget(self, action: "switchChanged:", forControlEvents: UIControlEvents.ValueChanged)
}
func configureCell(task: Tasks) {
taskImage.image = UIImage(named: "Icon.png")
arrowImage.image = UIImage(named: "arrow_filled.png")
dueDateLabel.text = "Due Date:"
dueDateValue.text = task.taskDate
dueTimeLabel.text = "Due Time:"
dueTimeValue.text = task.taskTime
taskNameValue.text = task.taskName
taskCellStatus.text = task.status
//taskCellStatus.hidden = true
if (taskCellStatus.text == "Completed") {
taskCellSwitchDisplay.on = true
} else {
taskCellSwitchDisplay.on = false
}
}
func switchChanged(taskCellSwitchDisplay: UISwitch) {
_ = taskCellSwitchDisplay.on
if taskCellSwitchDisplay.on == true {
let switchValue = "Completed"
print("Switch Variable: \(switchValue)")
delegate.didChangeSwitchState(self, isOn: true)
} else {
let switchValue = "Active"
print("Switch Variable: \(switchValue)")
delegate.didChangeSwitchState(self, isOn: false)
}
}
Here is where I am getting the delegate in my tableview
extension TaskCell: SettingCellDelegate {
func didChangeSwitchState(sender: TaskCell, isOn: Bool) {
if isOn == true {
print("true")
} else {
print("false")
}
}

Segmented Control in Calculator

Im trying to make a Segmented Control that holds two values, but I'm having trouble making it. I want to multiply the input by whatever side is picked in the segmented view and displayed in the label, but I keep running into errors. Any help?
#IBOutlet var input: UITextField!
#IBOutlet var output: UILabel!
#IBOutlet var controller: UISegmentedControl!
#IBAction func convert(sender: UIButton) {
}
#IBAction func change(sender: AnyObject) {
if controller.selectedSegmentIndex == 0 {
result = number1 * 1
}
if controller.selectedSegmentIndex == 1 {
result = number1 * 5
}
let number1 = Double(input.text!)
label.text = "\(result)"
}
Why you use "number1" before declaration?
Try this:
#IBOutlet var input: UITextField!
#IBOutlet var output: UILabel!
var result:Double! //fixed "cannot be applied to Double and Int." problem
#IBOutlet var controller: UISegmentedControl!
#IBAction func convert(sender: UIButton) {
}
#IBAction func change(sender: AnyObject) {
let number1 = Double(input.text!)
if controller.selectedSegmentIndex == 0 {
self.result = number1 * 1
}
if controller.selectedSegmentIndex == 1 {
self.result = number1 * 5
}
label.text = "\(result)"
}

Resources