Swift: Tracking User's score - swift

I'm trying to create a Quiz app that consists of two buttons, false and true button. My question is, as I answer more questions in the app, I want the textLabel to keep track of my score. And then when I circle back to the first question again, it should reset. This is my code so far. I'm looking forward to your answers.
class ViewController: UIViewController {
#IBOutlet weak var questionLabel: UILabel!
#IBOutlet weak var progressBar: UIProgressView!
#IBOutlet weak var trueButton: UIButton!
#IBOutlet weak var falseButton: UIButton!
#IBOutlet weak var scoreLabel: UILabel!
var quizBrain = QuizBrain()
override func viewDidLoad() {
super.viewDidLoad()
updateUI()
progressBar.progress = 0.0
}
#IBAction func answerButtonPressed(_ sender: UIButton) {
let userAnswer = sender.currentTitle
let userGotItRight = quizBrain.checkAnswer(userAnswer!)
if userGotItRight {
sender.shortChangeTo(.green)
} else {
sender.shortChangeTo(.red)
}
quizBrain.nextQuestion()
DispatchQueue.main.asyncAfter(deadline: .now() + 0.1) {
self.updateUI()
}
}
func updateUI() {
questionLabel.text = quizBrain.getQuestionText()
trueButton.backgroundColor = UIColor.clear
falseButton.backgroundColor = UIColor.clear
progressBar.progress = 33
scoreLabel.text = "Score: \(quizBrain.getScore)"
}
}

You don't have any code for it yet? You can create a struct like user
struct user {
var score: Int = 0
mutating func answerRight (){
self.score =+ 1 }
mutating func reset (){
self.score = 0 }
}
But I see this in your code "Score: (quizBrain.getScore)"
This says that quizBrain should know the score. But you never add a value to it So check your quizBrain and create a function or an object that can track the score and then call it here "if userGotItRight {}"

Related

What does this error "Thread 1: EXC_BAD_ACCESS (code=2, address=0x30d51fff8)" mean? How do I fix it

import UIKit
class ViewController: UIViewController {
#IBOutlet weak var triviaLabel: UILabel!
#IBOutlet weak var trueButton: UIButton!
#IBOutlet weak var falseButton: UIButton!
#IBOutlet weak var progressBar: UIProgressView!
var quiz = [Question(text: "Blah blah", answer: "True"),
Question(text: "Ha ha", answer: "True"),Question(text: "Bruh bruh", answer: "False")]
var questionNumber = 0
override func viewDidLoad() {
super.viewDidLoad()
updateQuestion()
}
#IBAction func answerButtonPressed(_ sender: UIButton) {
let userAnswer = sender.currentTitle
let actualAnswer = quiz[questionNumber].answer
if userAnswer == actualAnswer {
} else {
}
if questionNumber < quiz.count-1 {
questionNumber += 1
}else {
questionNumber = 0
}
updateQuestion()
}
func updateQuestion() {
triviaLabel.text = quiz[questionNumber].text // Get the error here
updateQuestion()
}
}
The build succeeds and the app launches but there comes a blank screen and the error occurs. I tried mapping the label again with the storyboard. I speculate that there is some problem with the label declaration or connection.

Passing boolean from one View controller to another, both controlled by a Tab Controller

I've been looking at other questions/answers around this and I can't seem to find an answer thats worked for me. I'm making a game where you click a pizza and you generate money. You start off with only being able to generate one dollar through clicking but as you purchase Upgrades this number gains in value. In theory, when you click the level 1 upgrade button it will send a true value to the main game view, making a click earn 5 dollars instead of 1.
import UIKit
class GameViewController: UIViewController {
var wallet: Int = 0
var totalIncome: Int = 0
var level1UpgradeUsed: Bool = false
#IBOutlet weak var pizzaButton: UIButton!
#IBOutlet weak var labelWallet: UILabel!
override func viewDidLoad() {
super.viewDidLoad()
print(level1UpgradeUsed)
// Do any additional setup after loading the view.
}
#IBAction func pizzaClick(_ sender: Any) {
let upgrades = UpgradesViewController()
let level1UpgradeUsed = upgrades.level1used
if level1UpgradeUsed == true {
wallet = wallet + 4
}
wallet = wallet + 1
labelWallet.text = ("$" + String(wallet))
}
In the upgrades controller I'm trying to send the true value once the button is clicked
import UIKit
class UpgradesViewController: UIViewController {
public var level1used: Bool = false
public var level2used: Bool = false
public var level3used: Bool = false
public var level4used: Bool = false
var level5used: Bool = false
#IBOutlet weak var buttonLevel1: UIButton!
#IBOutlet weak var buttonLevel2: UIButton!
#IBOutlet weak var buttonLevel3: UIButton!
#IBOutlet weak var buttonLevel4: UIButton!
#IBOutlet weak var buttonLevel5: UIButton!
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
}
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if let gameViewController = segue.destination as? GameViewController {
gameViewController.level1UpgradeUsed = self.level1used
}
}
#IBAction func Level1Click(_ sender: Any) {
if level1used == false{
buttonLevel1.backgroundColor = UIColor.gray
level1used = true
}
else {
}
}
Im geussing I'm not utilizing the TabBarController to pass data and not sure at all how to go about doing that. I'm new to swift and teaching myself everything so I'm sorry if this seems like a redundant question. It feels like it should be a lot simpler then it looks.

Sigbart error during prepare for segue/unwind segue

I have an app where it is a marketplace and when you click on a product, it opens a detail view controller passing the data to display on the DetailVC. Additionally, inside the DetailVC, if you click on a button to claim the product, it segues to another VC to finalize the transaction.
In the DetailVC, there is a back button which is an unwind segue back to the main marketplace VC. Inside the TransactionVC, there is a cancel button which takes you back to the DetailVC.
When I am clicking the backButton in the DetailVC to take me back to the main market VC but I am getting a SIGBART Error and this :
020-07-15 09:05:23.707490-0500 evolutionatx[707:141952] Could not cast value of type 'evolutionatx.MarketplaceViewController' (0x1032c7868) to 'evolutionatx.PopUpPurchaseViewController' (0x1032c7ba8).
Here is the code for the DetailVC
import UIKit
import iCarousel
import CoreData
class MarketDetailViewController: UIViewController, UIScrollViewDelegate, iCarouselDelegate, iCarouselDataSource {
var productImageArray = [UIImage]()
var productVideo = String()
var pointsToPurchase = String()
var productName = String()
var productDescription = String()
var companyLogo = UIImage()
var companyWebsite = String()
var additionalProductImage = [UIImage]()
var companyName = String()
var promoCODE = String()
var buyLink = String()
var slides:[Slide] = [];
//IB
#IBOutlet weak var productNameLabel: UILabel!
#IBOutlet weak var productPriceLabel: UILabel!
#IBOutlet weak var productDescLabel: UILabel!
#IBOutlet weak var claimButton: UIButton!
#IBOutlet weak var imgScrollView: UIScrollView!
#IBOutlet weak var websiteButton: UIButton!
#IBOutlet weak var pageControl: UIPageControl!
#IBOutlet weak var logoDisplay: UIImageView!
#IBOutlet weak var carouselView: iCarousel!
#IBOutlet weak var otherProductslabe: UILabel!
var carouselImages = [UIImage]()
var evoCoin = Int()
override func awakeFromNib() {
super.awakeFromNib()
carouselImages = productImageArray
}
override func viewDidLoad() {
super.viewDidLoad()
valueSetter()
imgScrollView.delegate = self
slides = createSlides()
setupSlideScrollView(slides: slides)
pageControl.numberOfPages = slides.count
pageControl.currentPage = 0
view.bringSubviewToFront(pageControl)
}
}
func scrollViewDidScroll(_ scrollView: UIScrollView) {
let pageIndex = round(scrollView.contentOffset.x/view.frame.width)
pageControl.currentPage = Int(pageIndex)
let maximumHorizontalOffset: CGFloat = scrollView.contentSize.width - scrollView.frame.width
let currentHorizontalOffset: CGFloat = scrollView.contentOffset.x
// vertical
let maximumVerticalOffset: CGFloat = scrollView.contentSize.height - scrollView.frame.height
let currentVerticalOffset: CGFloat = scrollView.contentOffset.y
let percentageHorizontalOffset: CGFloat = currentHorizontalOffset / maximumHorizontalOffset
let percentageVerticalOffset: CGFloat = currentVerticalOffset / maximumVerticalOffset
}
#IBAction func claimProduct(_ sender: Any) {
print("tap rec")
claimProductandPurchase()
}
func claimProductandPurchase(){
evoCOiner()
if(evoCoin >= Int(pointsToPurchase)!){
print("Transaction Successful")
performSegue(withIdentifier: "proceedQuestion", sender: self)
}
else{
showToast(controller: self, message: "Insufficient EvoCoins", seconds: 0.5)
}
}
func showToast(controller: UIViewController, message : String, seconds: Double) {
let alert = UIAlertController(title: nil, message: message, preferredStyle: .alert)
alert.view.backgroundColor = UIColor.black
alert.view.alpha = 0.6
alert.view.layer.cornerRadius = 15
controller.present(alert, animated: true)
DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + seconds) {
alert.dismiss(animated: true)
}
}
func evoCoiner(){
let context = (UIApplication.shared.delegate as! AppDelegate).persistentContainer.viewContext
let request = NSFetchRequest<NSFetchRequestResult>(entityName: "EvoCoins")
request.returnsObjectsAsFaults = false
do{
let result = try context.fetch(request)
for data in result as! [NSManagedObject]
{
evoCoin = data.value(forKey: "evoCoins") as! Int
}
}catch{
print("Failed")
}
}
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
let detailController = segue.destination as! PopUpPurchaseViewController
detailController.ppromo = promoCODE
detailController.link = buyLink
detailController.coinToPurchase = Int(pointsToPurchase)!
}
//This is the unwind used by the transaction back button
#IBAction func unwindToItem(segue: UIStoryboardSegue) {
}
}
Here is the code in the transaction VC
import UIKit
import AMTabView
import CoreData
class MarketplaceViewController: UIViewController, TabItem {
#IBOutlet weak var sView: UIView!
#IBOutlet weak var evoCoinLabe: UILabel!
//For the sake of simplicity I only kept the Unwind functions
//MARK: - UNWIND FUNCTIONS
#IBAction func unwindToMainMarketView(segue: UIStoryboardSegue) {
}
}
How can I fix this error?
Please advise if my question was not clear or properly phrased (if so, sorry I am pretty new to all of this)
As #matt already said in his comment and the error clearly states, you cannot cast a MarketplaceViewController to a PopUpPurchaseViewController.
Furthermore instead of doing a forced cast, always look for a safe one like below. Doing so will prevent crashes.
if let detailController = segue.destination as? PopUpPurchaseViewController {
...
}
else {
// log failed to cast
}

Swift Combine question with UILabel subscribe

import UIKit
import Combine
class ViewController: UIViewController {
#IBOutlet weak var allowMessageSwitch: UISwitch!
#IBOutlet weak var sendButton: UIButton!
#IBOutlet weak var messageLabel: UILabel!
#Published var canSendMessages: Bool = false
#Published var newMsg: String = ""
private var switchSubscriber: AnyCancellable?
private var btnSubscriber: AnyCancellable?
override func viewDidLoad() {
allowMessageSwitch.isOn = false
super.viewDidLoad()
setupProcesscingChain()
}
func setupProcesscingChain() {
switchSubscriber = $canSendMessages.receive(on: DispatchQueue.main).assign(to: \.isEnabled, on: sendButton)
btnSubscriber = $newMsg.receive(on: DispatchQueue.main).assign(to: \.text, on: messageLabel)
}
#IBAction func didSwitch (_ sender: UISwitch) {
canSendMessages = sender.isOn
}
#IBAction func sendMessage( _ sender: Any) {
}
}
I am getting error in
btnSubscriber = $newMsg.receive(on: DispatchQueue.main).assign(to: \.text, on: messageLabel)
error msg is
Type of expression is ambiguous without more context
I dont understand why label does not work as Switcher (bool)
I assume it is because \.isEnabled is not optional, and \.text is optional..??
how can I make this work with the same format. this is for practice and to understand how Combine works.. please help!
lableSubscriber = $newMsg.receive(on: DispatchQueue.main).assign(to: \.text!, on: messageLabel)
I solved it on my own! it was very simple.
just force unwrap the keyPath.

Cannot convert value of type 'String?' to type 'NSString' in coercion

Im trying to make this calculator for various math formulas and I'm stuck at this point. I was following this tutorial
Here's my code:
import UIKit
class pythagorasViewController: UIViewController {
#IBOutlet weak var aLabel: UILabel!
#IBOutlet weak var bLabel: UILabel!
#IBOutlet weak var aField: UITextField!
#IBOutlet weak var bField: UITextField!
#IBOutlet weak var answerLabel: UILabel!
#IBAction func calculateButton(_ sender: UIButton) {
var a = (aField.text as NSString).floatValue
var b = (bField.text as NSString).floatValue
var answer = sqrt(a*a + b*b)
answerLabel.text = "\(answer)"
}
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.
}
}
The part where I'm getting the error is at:
var a = (aField.text as NSString).floatValue
var b = (bField.text as NSString).floatValue
Prefer let to var when possible. You do not need to use NSString. You can cast String to Float?. You need to unwrap both the text property which is a String? (if you have a question about the type of a variable option click and it will show you) and the Float? conversion:
func calculateButton(_ sender: UIButton) {
guard let aText = aField.text,
let bText = bField.text,
let a = Float(aText),
let b = Float(bText) else {
return
}
let answer = sqrt(a*a + b*b)
answerLabel.text = "\(answer)"
}