Trying to add multiple Uitextfields as integers [duplicate] - ios

This question already has answers here:
Sum of 3 UITextField? [closed]
(2 answers)
Closed 4 years ago.
I am having trouble turning my Uitextfields into integers. I am trying to add them to get a total score for hole 2 and hole 3? Do you all have any ideas? I have tried Int(hole.text) and many other variations, but i keep getting errors.
//
// ViewController.swift
// Savetext5
//
// Created by Brendan Berkowitz on 1/31/19.
// Copyright © 2019 Brendan Berkowitz. All rights reserved.
//
import UIKit
class ViewController: UIViewController {
//hole one
#IBOutlet weak var playername: UITextField!
#IBAction func saveButton(_ sender: Any) {
UserDefaults.standard.set(playername.text, forKey: "playonename")}
#IBAction func deleteButton(_ sender: Any) {
UserDefaults.standard.removeObject(forKey: "playonename")}
// hole 2
#IBOutlet weak var holetwo: UITextField!
#IBAction func saveButton2(_ sender: Any) {
UserDefaults.standard.set(holetwo.text, forKey: "holetwo")}
#IBAction func deleteButton2(_ sender: Any) {
UserDefaults.standard.removeObject(forKey: "holetwo")}
// hole 3
#IBOutlet weak var holethree: UITextField!
#IBAction func savebutton3(_ sender: Any) {UserDefaults.standard.set(holethree.text, forKey: "holethree")}
#IBAction func deletebutton3(_ sender: Any) {UserDefaults.standard.removeObject(forKey: "holethree")}
override func viewDidLoad() {
super.viewDidLoad()
//hole one
let savedName = UserDefaults.standard.object(forKey: "playonename")
if let playeronename = savedName as? String {
playername.text = playeronename
}
// Hole two
let savedholetwoname = UserDefaults.standard.object(forKey: "holetwo")
if let holetwoname = savedholetwoname as? String {
holetwo.text = holetwoname
}
// hole three
let savedholethreename = UserDefaults.standard.object(forKey: "holethree")
if let holethreename = savedholethreename as? String {
holethree.text = holethreename
}
}
}

There are many solutions you can choose. But before you are going to convert the textfield's text to Int, you should do some checking and handling
e.g Is text empty? Is the text's format valid?
// define utility function
extension UITextField {
var textToInt: Int {
// return 0 as default value
return Int(text ?? "0") ?? 0
}
}
class ViewController: UIViewController {
func totalScore() -> Int {
return holetwo.textToInt + holethreename.textToInt
}
}

let textFieldOne = UITextField()
let textFieldTwo = UITextField()
let sum: Int = {
if let scoreOne = Int(textFieldOne.text ?? "0"), let scoreTwo = Int(textFieldTwo.text ?? "0") {
return scoreOne + scoreTwo
}
return 0
}()

Related

How to Check Answer in a Quiz when the Button isSelected

I'm new to Swift and Coding. My english is not so good so apologize in advance!
I want to build a Quiz App. Now I have some trouble with checking the correct Answer because my uibuttons can be selected. The Reason for that ist that I would like to have multiple Answers with multiple Choice and multiple correct answers.
I don't know what kind of Informationen of my Code do you need from me but I will post what I mean it could help.
Thank you so much in advance for your help!!!
Class
import Foundation
class Quiz {
let question: String
let options : [String]
let correctAnswer: [String]
init(question: String, options: [String], correctAnswer: [String]) {
self.question = question
self.options = options
self.correctAnswer = correctAnswer
}
func validateOption(_ index: Int) -> Bool {
let answer = options[index]
return answer == correctAnswer[index]
}
deinit {
}
}
My Viewcontroller
import UIKit
class ViewController: UIViewController {
#IBOutlet weak var quenstionLabel: UILabel!
#IBOutlet var answerButton: [UIButton]!
let quizManager = QuizManager()
override func viewDidLoad() {
super.viewDidLoad()
getNewQuiz()
}
#IBAction func checkAnswerButtonTapped(_ sender: UIButton) {
}
#IBAction func checkMarkAnswerClicked(_ sender: UIButton) {
if sender.isSelected {
sender.isSelected = false
} else {
sender.isSelected = true
}
}
and my Quiz Manager
import Foundation
class QuizManager {
private var quiz: Quiz!
private var _totalAnswers = 0
private var _totalCorrectAnswers = 0
var question: String {
return quiz.question
}
var options: [String] {
return quiz.options
}
var totalAnswers: Int {
return _totalAnswers
}
var totalCorrectAnswers: Int {
return _totalCorrectAnswers
}
func refreshQuiz(){
let randomIndex = Int(arc4random_uniform(UInt32(quizes.count)))
let quizData = quizes[randomIndex]
quiz = Quiz(question: quizData.question, options: quizData.options, correctAnswer: quizData.correctAnswer)
}
func validateAnswer(index: Int){
_totalAnswers += 1
if quiz.validateOption(index){
_totalCorrectAnswers += 1
}
}
If there are needed more Informations, please let me know!!
It would be great, if someone could help me.
You can solve this problem following these steps.
Add an array for your answers in Question Class.
Second Add Delegate in your cell class that will notify your view controller
implement that delegate in view controller and append answers to your model.
On check button tapped simply compare array of your tapped answers with correct answers array.
//Step 1
var myAnswers:[String]
protocol CheckAnswerDelegate : class {
func didPressOptionButton(myAnswer: String)
}
#IBAction func buttonPressed(_ sender: UIButton) {
checkAnswerDelegate?.didPressOptionButton(myAnswer: self.answerButton.titleLabel?.text ?? "")
}
class ViewController: UIViewController,UITableViewDelegate, UITableViewDataSource, CheckAnswerDelegate {}
func didPressOptionButton(myAnswer: String) {
if question1.myAnswers.contains(myAnswer) {
if let firstIndex = question1.myAnswers.firstIndex(where: {$0 == myAnswer}) {
question1.myAnswers.remove(at: firstIndex)
}
}else {
question1.myAnswers.append(myAnswer)
}
self.answerView.reloadData()
}
What I would do is put all of your answer buttons in a list. Then, inside checkAnswerButtonTapped you can run through the list and see which ones of them have isSelected set to true.
for button in buttonList {
var answersSelected = []
if button.isSelected {
answersSelected.append(button.text)
// You may want something different here depending on how the buttons store the answer options
}
}
Once you're done with that, compare them with the predefined correct answers from your QuizManager.
One other thing you could do to make your life a little bit easier is using the .toggle() function with your Boolean variables. Basically it just switches the value of your variable. So in your checkMarkAnswerClicked you could just have sender.isSelected.toggle()

Error when try to unwrap realm object

I have following issue when I try to use data from one of Realm Objects
I have an error:
Thread 1: Fatal error: Unexpectedly found nil while unwrapping an Optional value
I'm confused because when I try to do it manually on debug console all works fine
(lldb) print meal?.mealName
(String?) $R0 = "Krem buraczany"
I will attach whole code and show you on which line error appear
Realm Object:
import UIKit
import RealmSwift
class Meal: Object {
#objc dynamic var mealID : String = ""
#objc dynamic var mealName : String = ""
var ingredients = List<String>()
var mealDescription = List<String>()
#objc dynamic var kcal : Int = 0
#objc dynamic var preparingTime : Int = 0
#objc dynamic var imageName : String = ""
convenience init(mealID: String, mealName: String, kcal: Int, preparingTime: Int, imageName: String) {
self.init()
self.mealID = mealID
self.mealName = mealName
self.kcal = kcal
self.preparingTime = preparingTime
self.imageName = imageName
}
override static func primaryKey() -> String? {
return "mealID"
}
}
Sending data via segue:
#IBAction func ideaForMealButtonPressed(_ sender: UIButton) {
performSegue(withIdentifier: "ideaForMeal", sender: self)
}
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
let destinationVC = segue.destination as! IdeaForMeal
destinationVC.randomMeal = getRandomMeal()
}
func getRandomMeal() -> String {
var mealsCount = realm.objects(Meal.self).count
mealsCount += 1
let randomMealID = arc4random_uniform(UInt32(mealsCount))
print (randomMealID)
return String(randomMealID)
}
Receiver:
//Global Variables
let realm = try! Realm()
var randomMeal : String? {
didSet {
let selectedMeal = downloadMealData(mealID: randomMeal!)
setUIForMeal(meal: selectedMeal)
}
}
override func viewDidLoad() {
super.viewDidLoad()
self.hideKeyboardWhenTappedAround()
}
//Background Operations
func downloadMealData(mealID: String?) -> Meal? {
let currentMeal = realm.object(ofType: Meal.self, forPrimaryKey: mealID)
return currentMeal
}
func checkPositionOfTopIngredientsLabel() -> CGFloat {
let maxY = ingredientsTopLabel.frame.maxY
return maxY
}
func setUIForMeal(meal: Meal?) {
mealNameLabel.text = meal!.mealName // Error!
mealImage.image = UIImage(named: meal!.imageName)
preparingTimeLabel.text = String(meal!.preparingTime)
kcalLabel.text = String(meal!.kcal)
}
Thanks!
BR
iMat
The error is not related to Realm. It's a very common view life cycle mistake.
Setting randomMeal in the destination view controller triggers the didSet observer. The observer is going to access an IBOutlet which is not connected yet.
A solution is to run the code in viewDidLoad
var randomMeal = ""
override func viewDidLoad() {
super.viewDidLoad()
self.hideKeyboardWhenTappedAround()
if !randomMeal.isEmpty {
let selectedMeal = downloadMealData(mealID: randomMeal)
setUIForMeal(meal: selectedMeal)
}
}

Fatal error when unwrapping a segued string (swift3)

This is my code I don't know what I did wrong. All of the problems are in function steve. LebelText is a timer timer label that is segued from another view controller. So i want to take lebetText convert it to a int to subtract 1 from it then reconvert it back to a string to display the number.
This is view Controller a. The texted being segued is lebelText.
import UIKit
class testViewController: UIViewController {
#IBOutlet var lazel: UILabel!
#IBOutlet var plax: UIButton!
#IBOutlet var stopx: UIButton!
var timer = Timer()
var counter = 0.0
var isRunning = false
override func viewDidLoad() {
super.viewDidLoad()
}
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
let DestViewController : restultViewController = segue.destination as! restultViewController
DestViewController.LebelText = lazel.text!
}
#IBAction func play(_ sender: Any) {
if !isRunning{
timer = Timer.scheduledTimer(timeInterval: 0.1, target: self, selector: #selector(testViewController.update), userInfo: nil, repeats: true)
}
plax.isEnabled = false
stopx.isEnabled = true
}
#IBAction func stop(_ sender: Any) {
plax.isEnabled = true
stopx.isEnabled = false
timer.invalidate()
isRunning = false
}
func update(){
counter += 0.1
lazel.text = String(format: "1%f", counter)
lazel.text = "\(counter)"
}}
this is view controller b. The goal is to go to take lebelText convert it to a int to subtracted 1 from it. Then convert it back to a string so it can be displayed.
import UIKit
class restultViewController: UIViewController {
#IBOutlet var dxe: UILabel!
var LebelText = String()
let myInt = Int()
override func viewDidLoad() {
super.viewDidLoad()
steve()
}
func steve(){
var eq = LebelText
var intValue = Int(eq)
let vx = intValue! - 1
let ramit = String(vx)
dxe.text = ramit
}
ok so to get rid of the optional and to be sure it all works you should do like
if let intValue = Int(eq) {
vx = intValue - 1
dxe.text = String(vx)
} else {
//do some stuff if you cannot convert eq to Int
}
but I would recommend you to start with some easier tasks, it looks like you did not completely learn basics.
import UIKit
class restultViewController: UIViewController {
#IBOutlet var someLabel: UILabel!
public var myText: String?
override func viewDidLoad() {
super.viewDidLoad()
self.parseData()
}
private func parseData(){
guard let unwrapedText = self.myText else {
//you didn't pass string
return
}
if let myInt = Int(unwrapedText) {
myInt = myInt - 1
self.someLabel.text = String(myInt)
} else {
//you string is not convertable to int
}
}
}
You Can just do this.
import UIKit
class restultViewController: UIViewController {
#IBOutlet var dxe: UILabel!
var LebelText = String()
let myInt = Int()
override func viewDidLoad() {
super.viewDidLoad()
steve()
}
func steve(){
var eq = Int(LebelText.text)
eq = eq - 1
dxe.text = String(eq)
}

Having problems with saving and loading in Swift 3.0 iOS 10

I'm really new to the Swift and iOS programming scene and I am trying to learn a bunch of things. For this app, I want to save and load just one integer, but I am having problems, as everything I found on stack overflow and the Internet just doesn't seem to work on Swift 3. The app crashes immediately, it breaks on:
#IBOutlet weak var StaticLabel: UILabel!
It says "Thread 1: breakpoint 3.5" . Any help and tips would be very much appreciated :)
import UIKit
import AVFoundation
var player: AVAudioPlayer?
var number = 0
class ViewController: UIViewController {
#IBOutlet weak var StaticLabel: UILabel!
#IBOutlet weak var NumberLabel: UILabel!
let defaults = UserDefaults.standard
override func viewDidLoad() {
super.viewDidLoad()
Load()
}
func Load()
{
number = defaults.integer(forKey: "Save")
NumberLabel.text = String(number)
}
func playSound()
{
let path = Bundle.main.path(forResource: "RightYouAre.mp3", ofType: nil)
let url = URL(fileURLWithPath: path!)
do {
let sound = try AVAudioPlayer(contentsOf: url)
player = sound
sound.play()
}
catch {
// couldn't load file :(
}
}
#IBAction func Minus(_ sender: AnyObject) {
number = number - 1
NumberLabel.text = String(number)
defaults.set(number, forKey: "Save")
}
#IBAction func Plus(_ sender: UIButton) {
playSound()
number = number + 1
NumberLabel.text = String(number)
defaults.set(number, forKey: "Save")
}
}
your line of code
number = defaults.integer(forKey: "Save")
user defaults integer for key Save is nil, actually this key does not exist at all in the user defaults
before you load this integer from user defaults , it has to be set first
if defaults.object(forKey: "Save") != nil { number = defaults.integer(forKey: "Save") }
this will make sure the object exists in the user defaults before getting it's value
finally your load function should be
func Load()
{
if defaults.object(forKey: "Save") != nil
{
number = defaults.integer(forKey: "Save")
NumberLabel.text = String(number)
}
}
You need to add null handling to the load function as first time there
will be no value for the key "save" in your UserDefaults.
func Load()
{
if let number = defaults.integer(forKey: "Save")
{
self.number = number
NumberLabel.text = String(number)
}
}

NSUserDefaults in Swift won't save my data the way my code currently is. What's my issue?

This is my code on the view controller with the total score:
import UIKit
var playerName = ""
var totalScore = 0
var bestPlayer = "Taipan"
var highScore = 100
var myNumber: NSInteger = highScore
var myName: NSString = bestPlayer
class StartVC: UIViewController, UITextFieldDelegate {
override func viewDidLoad() {
super.viewDidLoad()
}
#IBOutlet weak var lblPlayerName: UILabel!
#IBOutlet weak var lblNameScore: UILabel!
#IBOutlet weak var txtPlayerName: UITextField!
#IBAction func btnPlay(sender: UIButton) {
if txtPlayerName.text == "" {
lblPlayerName.text = "Please enter your name!"
} else {
playerName = txtPlayerName.text
performSegueWithIdentifier("StartingStatsVC", sender: self)
}
}
func textFieldShouldReturn(textField: UITextField) -> Bool {
txtPlayerName.resignFirstResponder()
return true
}
override func touchesBegan(touches: NSSet, withEvent event: UIEvent) {
self.view.endEditing(true)
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
override func viewWillAppear(animated: Bool) {
NSUserDefaults.standardUserDefaults().setObject(myNumber, forKey: "fixedHighScore")
NSUserDefaults.standardUserDefaults().setObject(myName, forKey: "fixedPlayerName")
NSUserDefaults.standardUserDefaults().synchronize()
var myscore: AnyObject? = NSUserDefaults.standardUserDefaults().objectForKey("fixedHighScore")
var myplayer: AnyObject? = NSUserDefaults.standardUserDefaults().objectForKey("fixedPlayerName")
NSUserDefaults.standardUserDefaults().synchronize()
lblNameScore.text = String(myplayer as NSString) + ": " + String(myscore as NSInteger)
}
}
This is the code in a different view controller which will replace the highscore and bestplayer if the score is higher than the total:
if totalScore > Int(myNumber as NSNumber) {
myNumber = totalScore
myName = playerName
}
Everything works except for saving the highscore and the bestplayer which is the whole point of using NSUserDefaults. Please let me know what to change for it to save correctly when the app is closed then brought up again.
The problem is that you're setting the object of your two user default keys to myNumber and myName every time the view first appears (in viewWillAppear). You should use registerDefaults, to only add those initial values, if there aren't already values in the dictionary,
override func viewWillAppear(animated: Bool) {
let dict = ["fixedHighSCore":myNumber, "fixedPlayerName":myName]
NSUserDefaults.standardUserDefaults().registerDefaults(dict)
NSUserDefaults.standardUserDefaults().synchronize()
var myscore: AnyObject? = NSUserDefaults.standardUserDefaults().objectForKey("fixedHighScore")
var myplayer: AnyObject? = NSUserDefaults.standardUserDefaults().objectForKey("fixedPlayerName")
NSUserDefaults.standardUserDefaults().synchronize()
lblNameScore.text = String(myplayer as NSString) + ": " + String(myscore as NSInteger)
}
You also need to add the new values to the user defaults in your other controller (I don't know if you're already doing that, but just not showing it).
if totalScore > Int(myNumber as NSNumber) {
NSUserDefaults.standardUserDefaults().setObject(totalScore, forKey: "fixedHighScore")
NSUserDefaults.standardUserDefaults().setObject(playerName, forKey: "fixedPlayerName")
NSUserDefaults.standardUserDefaults().synchronize()
}

Resources