How to display a certain view depending on random number generation in swift? - swift

I am following a tutorial, this is the repo on git
I have 7 views, that represent the die. And 6 labels, that show the random number each time I press the dieButtonTapped() button. When I press the button, first label appears with the random number generated, which is good, but I can't get the appropriate view to show up. So, if the random number is 5, label shows up with the number 5 in it, and 5 views out of 7 should show up, representing the die.
What it is doing now is that it shows random views that do not match the random number showed on the label.
Please help me correct func rearrangeDie() function to match what func updateScore(roll: Int) is returning.
Thank you !
Here is my code:
class ViewController: UIViewController {
#IBOutlet weak var view1: UIView!
#IBOutlet weak var view2: UIView!
#IBOutlet weak var view3: UIView!
#IBOutlet weak var view4: UIView!
#IBOutlet weak var view5: UIView!
#IBOutlet weak var view6: UIView!
#IBOutlet weak var view7: UIView!
#IBOutlet weak var label1: UILabel!
#IBOutlet weak var label2: UILabel!
#IBOutlet weak var label3: UILabel!
#IBOutlet weak var label4: UILabel!
#IBOutlet weak var label5: UILabel!
#IBOutlet weak var label6: UILabel!
override func viewDidLoad() {
super.viewDidLoad()
view1.isHidden = true
view2.isHidden = true
view3.isHidden = true
view4.isHidden = true
view5.isHidden = true
view6.isHidden = true
view7.isHidden = true
label1.isHidden = true
label2.isHidden = true
label3.isHidden = true
label4.isHidden = true
label5.isHidden = true
label6.isHidden = true
}
#IBAction func dieButtonTapped(_ sender: AnyObject) {
rearrangeDie()
updateScore(roll: randomDiceRoll())
}
// Returns back a random Int (1, 2, 3, 4, 5, or 6)
func randomDiceRoll() -> Int {
return Int(arc4random_uniform(6) + 1)
}
func rearrangeDie() {
if randomDiceRoll() == 1 {
view7.isHidden = false
}
else if randomDiceRoll() == 2 {
view2.isHidden = false
view5.isHidden = false
}
else if randomDiceRoll() == 3 {
view2.isHidden = false
view7.isHidden = false
view5.isHidden = false
}
else if randomDiceRoll() == 4 {
view1.isHidden = false
view2.isHidden = false
view5.isHidden = false
view6.isHidden = false
}
else if randomDiceRoll() == 5 {
view1.isHidden = false
view2.isHidden = false
view5.isHidden = false
view6.isHidden = false
view7.isHidden = false
}
else if randomDiceRoll() == 6 {
view1.isHidden = false
view2.isHidden = false
view3.isHidden = false
view4.isHidden = false
view5.isHidden = false
view6.isHidden = false
}
}
func updateScore(roll: Int) {
let diceScore = String(roll)
if label1.isHidden {
label1.text = diceScore
label1.isHidden = false
}
else if label2.isHidden {
label2.text = diceScore
label2.isHidden = false
}
else if label3.isHidden {
label3.text = diceScore
label3.isHidden = false
}
else if label4.isHidden {
label4.text = diceScore
label4.isHidden = false
}
else if label5.isHidden {
label5.text = diceScore
label5.isHidden = false
}
else if label6.isHidden {
label6.text = diceScore
label6.isHidden = false
}
else {
viewDidLoad()
}
}
}

You are basically generating a new random number each time you call randomDiceRoll(). Store it in a variable and access it throughout the if statements.
I would also strongly suggest a programatically created layout and a serious refactoring.
func rearrangeDie() {
let randomDiceRoll = randomDiceRoll()
if randomDiceRoll == 1 {
view7.isHidden = false
}
else if randomDiceRoll == 2 {
view2.isHidden = false
view5.isHidden = false
}
else if randomDiceRoll == 3 {
view2.isHidden = false
view7.isHidden = false
view5.isHidden = false
}
else if randomDiceRoll == 4 {
view1.isHidden = false
view2.isHidden = false
view5.isHidden = false
view6.isHidden = false
}
else if randomDiceRoll == 5 {
view1.isHidden = false
view2.isHidden = false
view5.isHidden = false
view6.isHidden = false
view7.isHidden = false
}
else if randomDiceRoll == 6 {
view1.isHidden = false
view2.isHidden = false
view3.isHidden = false
view4.isHidden = false
view5.isHidden = false
view6.isHidden = false
}
}

#the4Kman is correct in stating that calling the randomDiceRoll() will generate a new random number every time which leads to the problem you are facing. What you need instead, is to merge your rearrangeDie() and updateScore() methods into one. Also, as #nanothread59 suggested, you should use IBOutletCollections.
You should declare your collections like this
//Notice that you cannot make them "weak" properties
#IBOutlet var views: Array<UIView>!
#IBOutlet var labels: Array<UILabel>!
Then give each of your view and label a tag from 1-7 in storyboard and connect them to their respective outletCollections. Once it is setup, you can merge your methods into one like this
func update() {
//Hide all Views and Labels
for item in views {
item.isHidden = true
}
for item in labels {
item.isHidden = true
}
//Get Random Value
let random = randomDiceRoll()
//UPDATE YOUR VIEWS' AND LABELS' HIDDEN PROPERTY AND VALUES HERE BASED ON THE RANDOM VALUE
//To access a particular view or label, you'll do something like this
for item in views {
if item.tag == {whatever} {
//DO SOMETHING
}
}
//Repeat the above loop for labels as well
}
P.S. With IBOutletCollections, your viewDidLoad will also change like this
override func viewDidLoad() {
super.viewDidLoad()
//Hide all Views and Labels
for item in views {
item.isHidden = true
}
for item in labels {
item.isHidden = true
}
}

Related

deselectd other button when one button isSeleted

I have three button link together called tipChanged .
one button was seleted by default (10%)
I want to write some code to make one button isSeleted ,the other two will automatically deseleted .my code work but too wordy ,any easy way ?
below is my code ,thanks in advance.
import UIKit
class CalculatorViewController: UIViewController {
#IBOutlet weak var zeroPctButton: UIButton!
#IBOutlet weak var tenPctButton: UIButton!
#IBOutlet weak var twentyPctButton: UIButton!
#IBAction func tipChanged(_ sender: UIButton) {
let pctChoosed = sender.currentTitle
if pctChoosed == "0%"{
zeroPctButton.isSelected = true
tenPctButton.isSelected = false
twentyPctButton.isSelected = false
}else if pctChoosed == "10%"{
zeroPctButton.isSelected = false
tenPctButton.isSelected = true
twentyPctButton.isSelected = false
}else{
zeroPctButton.isSelected = false
tenPctButton.isSelected = false
twentyPctButton.isSelected = true
}
}
}
Remove the if statement and just set them all to false. Then just under where they are set to false set sender.isSelected = true and you should get the desired results.

Unresolved Identifier 'count'

Here is the error that I am seeing.
The "cardButton" is responsible for showing the next question. This is a small card app game that I am trying to make and as you can see from the image this is where I am having the issue with the code.
Here is the code:
import UIKit
class MultipleViewController: UIViewController {
#IBOutlet weak var questionLabel2: UILabel!
#IBOutlet var answerButtons: [UIButton]!
#IBOutlet weak var cardButton: UIButton!
#IBAction func cardButtonHandle(_ sender: Any) {
cardButton.isEnabled = true
if questionIdx < count(mcArray) - 1 { // There are still more questions
questionIdx += 1 //
} else {
questionIdx = 0
}
nextQuestion()
}
#IBAction func answerButtonHandle(_ sender: UIButton) {
if sender.titleLabel?.text == correctAnswer{
sender.backgroundColor = UIColor.green
print("Correct!")
} else {
sender.backgroundColor = UIColor.red
print("Wrong Answer")
}
for button in answerButtons{
button.isEnabled = false
if button.titleLabel?.text == correctAnswer {
button.backgroundColor = UIColor.green
}
}
cardButton.isEnabled = true // next question
}
var correctAnswer: String? // correct answers
var answers = [String]() // answers
var question : String? // Questions
var questionIdx = 0 // not sure what this is ?
override func viewDidLoad() {
super.viewDidLoad()
// titleForButtons() // call buttons as soon its loaded..
cardButton.isEnabled = false
nextQuestion()
}
func nextQuestion (){
let currentQuestion = mcArray![questionIdx]
answers = currentQuestion["Answers"] as! [String]
correctAnswer = currentQuestion["CorrectAnswer"] as? String
question = currentQuestion["Question"] as? String
titleForButtons ()
}
func titleForButtons (){
for (idx,button) in answerButtons .enumerated() {
button.titleLabel?.lineBreakMode = .byWordWrapping
button.setTitle(answers[idx],for:.normal)
button.isEnabled = true
}
questionLabel2.text = question
}
}
The following should work, you did not have the correct syntax for the length of the array. Note that if you have not initialized your questions array, this would cause a crash. Therefore you might want to add a guard into your code. Perhaps use the following
#IBAction func cardButtonHandle(_ sender: Any) {
cardButton.isEnabled = true
if questionIdx < (mcArray!.count) - 1 { // There are still more questions
questionIdx += 1 //
} else {
questionIdx = 0
}
nextQuestion()
}

What's wrong with my Swift function?

I'm trying to make a dice roll game and I'm having issues getting certain rolls to show up. Currently it's incomplete, but my current rolls I've written code for aren't showing up properly. i.e. rolling a 4 presents a 3. I understand I need to refactor and I apologize for that abomination that is my function.
edit : It is incomplete at the moment... so I haven't added scenarios for the other rolls.
import UIKit
class ViewController: UIViewController {
#IBOutlet weak var one: UIView!
#IBOutlet weak var two: UIView!
#IBOutlet weak var three: UIView!
#IBOutlet weak var four: UIView!
#IBOutlet weak var five: UIView!
#IBOutlet weak var six: UIView!
#IBOutlet weak var seven: UIView!
#IBOutlet weak var labelOne: UILabel!
#IBOutlet weak var labelTwo: UILabel!
#IBOutlet weak var labelThree: UILabel!
#IBOutlet weak var labelFour: UILabel!
#IBOutlet weak var labelFive: UILabel!
#IBOutlet weak var labelSix: UILabel!
override func viewDidLoad() {
labelOne.isHidden = true
labelTwo.isHidden = true
labelThree.isHidden = true
labelFour.isHidden = true
labelFive.isHidden = true
labelSix.isHidden = true
one.isHidden = true
two.isHidden = true
three.isHidden = true
four.isHidden = true
five.isHidden = true
six.isHidden = true
seven.isHidden = true
super.viewDidLoad()
}
// Rearrange dice depending on what is rolled.
func rearrangeDie(){
if randomDiceRoll() == 1 {
six.isHidden = false
} else if six.isHidden == false {
six.isHidden = true }
if randomDiceRoll() == 2 {
one.isHidden = false
seven.isHidden = false }
else if one.isHidden == false &&
seven.isHidden == false {
self.one.isHidden = true
self.seven.isHidden = true
}
if randomDiceRoll() == 3 {
one.isHidden = false
six.isHidden = false
seven.isHidden = false }
else if one.isHidden == false && six.isHidden == false && seven.isHidden == false {
one.isHidden = true
six.isHidden = true
seven.isHidden = true
}
}
// Reveal labels as you roll
func textToLabel(roll:intmax_t) {
let diceScore = String(roll)
if labelOne.isHidden == true {
labelOne.text = diceScore
labelOne.isHidden = false
}
}
#IBAction func dice(_ sender: AnyObject) {
}
#IBAction func dieButtonTapped(_ sender: AnyObject) {
randomDiceRoll()
rearrangeDie()
print(randomDiceRoll())
}
// Returns back a random Int (1, 2, 3, 4, 5, or 6)
func randomDiceRoll() -> Int {
return Int(arc4random_uniform(6) + 1)
}
}
To many if statements in your code make it hard to read. Your sample is not complete and so is probably your question. Therefore I can just assume the following:
You want to display the dice roll as "eyes" or "dots"
Each dot is a UIView
Numbering is from top left to bottom, the center dot is number 7
So heres my suggested code:
func rearrangeDie(){
let roll = randomDiceRoll()
//1x2
//374
//5x6
//One is visible for 2, 3, 4, 5 and 6
//oxx
//xxx
//xxx
one.isHidden = roll == 1
//Two is visible for 4, 5 and 6
//xxo
//xxx
//xxx
two.isHidden = roll == 1 || roll == 2 || roll == 3
//...
//Seven is visible for 1, 3 and 5
//xxx
//xox
//xxx
seven.isHidden = roll == 2 || roll == 4 || roll == 6
}

I need help debugging this error - Maths Quiz for Kids

My school project is a children's maths game where it test them in addition, subtraction and multiplication. I have two VC's that are linked to the error. The error I keep having is that every time I choose any of the options it ignores all the other operations and follows the instructions for multiplication! I have tried everything and I'm getting frustrated with this application.
Option_VC
class Option_VC: UIViewController {
var addition_true: Bool = false
var subtract_true: Bool = false
var multiply_true: Bool = false
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if addition_true == true {
let nextVC: Quiz_VC = segue.destinationViewController as! Quiz_VC
nextVC.addition_true = true
}else if subtract_true == true {
let nextVC: Quiz_VC = segue.destinationViewController as! Quiz_VC
nextVC.subtract_true = true
}else {
let nextVC: Quiz_VC = segue.destinationViewController as! Quiz_VC
nextVC.multiply_true = true
}
}
#IBAction func addition_enter(sender: AnyObject) {
addition_true = true
multiply_true = false
subtract_true = false
}
#IBAction func subtract_enter(sender: AnyObject) {
subtract_true = true
addition_true = false
multiply_true = false
}
#IBAction func multiply_enter(sender: AnyObject) {
multiply_true = true
addition_true = false
subtract_true = false
}
}
Quiz_VC
class Quiz_VC: UIViewController {
#IBOutlet var n1_lbl: UILabel!
#IBOutlet var back: UIButton!
#IBOutlet var next: UIButton!
#IBOutlet var enter: UIButton!
#IBOutlet var answer_field: UITextField!
#IBOutlet var symbol_lbl: UILabel!
#IBOutlet var n2_lbl: UILabel!
#IBOutlet var comment_lbl: UILabel!
#IBOutlet var score_lbl: UILabel!
var addition_true: Bool = false
var subtract_true: Bool = false
var multiply_true: Bool = false
var enter_entered_true: Bool = false
var answer: UInt32 = 0
var finalanswer: UInt32 = 0
var n1: UInt32 = 0
var n2: UInt32 = 0
var count = 0
var score = 0
var temp: UInt32 = 0
var operation: String = ""
override func viewDidLoad() {
super.viewDidLoad()
back.hidden = true
next.hidden = true
if addition_true == true {
AdditionQuestions()
}else if subtract_true == true {
SubtractionQuestions()
}
if multiply_true == true && addition_true == false && subtract_true == false{
MultiplicationQuestions()
}
}
func Operation() {
if addition_true == true {
operation = "1"
}else if subtract_true == true {
operation = "2"
}else {
operation = "3"
}
switch operation {
case "1":
finalanswer = n1 + n2
case "2":
finalanswer = n1 - n2
case "3":
finalanswer = n1 * n2
default: break
}
}
func AdditionQuestions() {
n1 = arc4random_uniform(9)+1
n2 = arc4random_uniform(9)+1
n1_lbl.text = "\(n1)"
n2_lbl.text = "\(n2)"
symbol_lbl.text = "+"
score_lbl.text = ""
comment_lbl.text = ""
}
func SubtractionQuestions() {
n1 = arc4random_uniform(9)+1
n2 = arc4random_uniform(9)+1
symbol_lbl.text = "-"
if n2 > n1 {
temp = n1
n1 = n2
n2 = temp
}
n1_lbl.text = "\(n1)"
n2_lbl.text = "\(n2)"
}
func MultiplicationQuestions() {
n1 = arc4random_uniform(9)+1
n2 = arc4random_uniform(9)+1
symbol_lbl.text = "×"
n1_lbl.text = "\(n1)"
n2_lbl.text = "\(n2)"
}
func EndQuiz() {
if count > 3 {
enter.hidden = true
next.hidden = true
back.hidden = false
score_lbl.text = "Score: \(score)"
comment_lbl.text = "Completed Quiz"
}
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
#IBAction func enter_entered(sender: AnyObject) {
if answer_field.text != nil {
enter_entered_true = true
answer = UInt32(answer_field.text!)!
count = count + 1
Operation()
if answer != finalanswer {
comment_lbl.text = "Incorrect"
} else {
comment_lbl.text = "Correct"
score = score + 1
}
} else {
comment_lbl.text = "Enter a number!"
}
enter.hidden = true
next.hidden = false
}
#IBAction func next_entered(sender: AnyObject) {
if addition_true == true {
AdditionQuestions()
comment_lbl.text = ""
}else if subtract_true == true {
SubtractionQuestions()
comment_lbl.text = ""
}
if multiply_true == true && addition_true == false && subtract_true == false{
MultiplicationQuestions()
comment_lbl.text = ""
}
enter.hidden = false
next.hidden = true
EndQuiz()
}
}
When you hit one of the buttons (Add, Subtract or Multiply) then the application immediately performs prepareForSegue before it performs the action associated with those buttons. Therefore addition_true, subtraction_true and multiplication_true are all always false and the code falls through to the else clause which sets the multiplication option.
To get around this:
In the storyboard remove the segues from the three buttons.
Add a segue from the first view controller to the second one (control drag from the yellow circle at the top of the first view controller to the body of the second view controller).
Give the segue a name(highlight the segue and name it ("mainSegue" or something) in the Attributes Inspector)
In your code add the following line to the end of each of the three actions (addition_enter, etc.):
performSegueWithIdentifier("mainSegue", sender: self)
This will ensure that the segue is called after the button actions have been performed.
In your Quiz_VC class update viewDidLoad()
override func viewDidLoad() {
super.viewDidLoad()
back.hidden = true
next.hidden = true
if addition_true == true {
AdditionQuestions()
}else if subtract_true == true {
SubtractionQuestions()
}else if multiply_true == true{
MultiplicationQuestions()
}
}
and
func Operation() {
if addition_true == true {
operation = "1"
}else if subtract_true == true {
operation = "2"
}else if multiply_true == true {
operation = "3"
}
switch operation {
case "1":
finalanswer = n1 + n2
case "2":
finalanswer = n1 - n2
case "3":
finalanswer = n1 * n2
default: break
}
}
also
#IBAction func next_entered(sender: AnyObject) {
if addition_true == true {
AdditionQuestions()
comment_lbl.text = ""
}else if subtract_true == true {
SubtractionQuestions()
comment_lbl.text = ""
}else if multiply_true == true{
MultiplicationQuestions()
comment_lbl.text = ""
}else{
enter.hidden = false
next.hidden = true
EndQuiz()
}
}
I think that your #IBAction functions are not hooked up, or are not getting called because the button is linked to a segue.
This means that all of the Bools are false in prepareForSegue. And the logic in that function sets up the QuizVC for multiplication in that case (the last else clause does not have an if qualifier).
So, keep the segues in the storyboard. Populate the segue identifier string in the object inspector (the panel on the right in Xcode). Use, say, ADDITION_SEGUE, MULTIPLY_SEGUE, SUBTRACTION_SEGUE. You don't have to use caps and underscores, that's just my habit.
Then in prepareForSegue: you can tell which segue triggered the action. Set the properties on the QuizVC on the basis of that. Then you don't need those Bools at all in OptionVC.
In prepareForSegue:
if segue.identifier == "ADDITION_SEGUE" {
destinationViewController...
}
How about also putting an enum into QuizVC rather than using the Bools:
enum QuizType {
case Addition, Subtraction, Multiplication
}
That might make things a little easier in the long run. It kinda helps you manage state because the quiz type is only one of the three. Although, if the Bools work for you then fair enough.

Swift, Pass the array in uiPopoverController

I want to pass the array in my popovercontroller and sort the table view controller, sort it and give it back to the main controller.
My code for the popovercontroller
protocol MyProtocol
{
func refreshPageController(sortedProperties:[Property])
}
class SortingPopoverController: UIViewController
{
#IBOutlet var propertyNameView: UIView!
#IBOutlet var addressNameView: UIView!
#IBOutlet var imgSortingPropertyName: UIImageView!
#IBOutlet var propNameSrtImage: UIImageView!
#IBOutlet var addressSrtImage: UIImageView!
#IBOutlet var imgTickPropertyName: UIImageView!
#IBOutlet var imgTickAddress: UIImageView!
var properties:[Property] = [Property]()
var utility = Utility()
var srtProperties : [Property] = []
var mDelegate: MyProtocol?
override func viewDidLoad()
{
super.viewDidLoad()
println(properties.count)
let propertyNameSorting = UITapGestureRecognizer(target: self, action: "propertyNameSorting:")
self.propertyNameView.addGestureRecognizer(propertyNameSorting)
let addressSorting = UITapGestureRecognizer(target: self, action: "addressSorting:")
self.addressNameView.addGestureRecognizer(addressSorting)
imgTickPropertyName.hidden = true
imgTickAddress.hidden = true
}
func removeViewColorSelection(uiViewRef: UIView,tickImgShow: UIImageView)
{
uiViewRef.backgroundColor = utility.uicolorFromHex(0xF0F0F0)
uiViewRef.alpha = 0.97
tickImgShow.hidden = true
}
func addSelectedColorView(uiViewRef: UIView,tickImgShow: UIImageView)
{
uiViewRef.backgroundColor = UIColor.whiteColor()
uiViewRef.alpha = 0.97
tickImgShow.hidden = false
}
func propertyNameSorting(sender:UITapGestureRecognizer)
{
println("propertyNameSorting")
if propertyNameSrt == false
{
ascSorting == false
addSelectedColorView(propertyNameView,tickImgShow: imgTickPropertyName)
propertyNameSrt = true
removeViewColorSelection(addressNameView,tickImgShow: imgTickAddress)
addressSrt = false
if ascSorting == false
{
ascSorting = true
propNameSrtImage.image = UIImage(named: "sorting-ascending-22pt")
properties.sort(sorterForbuildingAsc)
}
else
{
ascSorting = false
propNameSrtImage.image = UIImage(named: "sorting-desending-22pt")
properties.sort(sorterForbuildingDesc)
}
}
else
{
if ascSorting == false
{
ascSorting = true
propNameSrtImage.image = UIImage(named: "sorting-ascending-22pt")
properties.sort(sorterForbuildingAsc)
}
else
{
ascSorting = false
propNameSrtImage.image = UIImage(named: "sorting-desending-22pt")
properties.sort(sorterForbuildingDesc)
}
}
mDelegate?.refreshPageController(properties)
}
func addressSorting(sender:UITapGestureRecognizer)
{
println("addressSorting")
if addressSrt == false
{
ascSorting = false
addSelectedColorView(addressNameView,tickImgShow: imgTickAddress)
propertyNameSrt = false
removeViewColorSelection(propertyNameView,tickImgShow: imgTickPropertyName)
addressSrt = true
if ascSorting == false
{
ascSorting = true
addressSrtImage.image = UIImage(named: "sorting-ascending-22pt")
}
else
{
ascSorting = false
addressSrtImage.image = UIImage(named: "sorting-desending-22pt")
}
}
else
{
if ascSorting == false
{
ascSorting = true
addressSrtImage.image = UIImage(named: "sorting-ascending-22pt")
}
else
{
ascSorting = false
addressSrtImage.image = UIImage(named: "sorting-desending-22pt")
}
}
}
Code to open the controller from the main controller
var sortingPopView = SortingPopoverController(nibName: "PopView",bundle: nil )
sortingPopView.properties = properties
var sortingPopoverController = UIPopoverController(contentViewController: sortingPopView)
sortingPopoverController.popoverContentSize = CGSize(width: 250, height: 100)
sortingPopoverController.presentPopoverFromBarButtonItem(sortingBtn, permittedArrowDirections: UIPopoverArrowDirection.Up
, animated: true)
Issue is I can't call main view controller method to sort the array.
You forgot to set the delegate on you PopoverViewController.
So when you are calling this in your PopOverController:
mDelegate?.refreshPageController(properties)
Nothing happens because mDelegate is nil
When creating the PopoverViewController you have set the delegate:
var sortingPopoverController = UIPopoverController(contentViewController: sortingPopView)
sortingPopoverController.mDelegate = self