Make variable equal to UserDefaults for timer - ios

I have a UIProgress view that takes 60 seconds to go across the screen, but how do I make it where rather than having a set time 'var seconds = 60' I have the UserDefault string be the time? (Not all the code is included.)
import UIKit
class MinuteMeditation: UIViewController {
#IBOutlet weak var progressController: UIProgressView!
#IBOutlet weak var statusLabel: UILabel!
#IBOutlet weak var timeLabel: UILabel!
let savedTime = UserDefaults.standard.string(forKey: "time")
var seconds = 60 // THIS IS WHERE I WANT THE USER DEFAULTS ^
var timer = Timer()
var isTimerRunning = false
var resumeTapped = false
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
runTimer()

One way is to assign the value at some point in the UIViewControllers life-cycle, for example, you could use viewWillLoad if you want to use the saved value EVERY time the view is shown, or viewLoaded if you only want to set when the view is first loaded by the system, for example...
class MinuteMeditation: UIViewController {
#IBOutlet weak var progressController: UIProgressView!
#IBOutlet weak var statusLabel: UILabel!
#IBOutlet weak var timeLabel: UILabel!
var seconds: TimeInterval = 60.0 // THIS IS WHERE I WANT THE USER DEFAULTS ^
var timer = Timer()
var isTimerRunning = false
var resumeTapped = false
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
if let savedTime = UserDefaults.standard.string(forKey: "time"), let time = Double(savedTime) {
seconds = time
}
}
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
runTimer()
}
}
Just remember, this will ALWAYS override any value previous set. If you prefer to only use the saved value if the value hasn't previously been set, you will need to make seconds optional and assign a default value when it hasn't previously been set and there is no saved value
Another option is to make seconds a computed value...
class MinuteMeditation: UIViewController {
#IBOutlet weak var progressController: UIProgressView!
#IBOutlet weak var statusLabel: UILabel!
#IBOutlet weak var timeLabel: UILabel!
var seconds: TimeInterval {
guard let savedTime = UserDefaults.standard.string(forKey: "time"), let time = Double(savedTime) else {
return 60.0
}
return time
}
var timer = Timer()
var isTimerRunning = false
var resumeTapped = false
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
runTimer()
}
}
This does mean that the value will never be settable directly, it will only be settable via the UserDefaults

Related

Updates on View Controller Disappear After Segue

I've been working through a project and have gotten most of the functionality straight, however there's one part that continues to stump me. I am using MVC format, and I have a two view controllers (one profile and one game). When progress is made on the game, the proper changes to game view controller show (i.e. button disappears and UI background color changes colors). However, when I segue to profile view controller using 'back' on navigation bar and return to the game view controller, the game view controller returns to the default without reflecting game progress.
I've tried unwinding segue, making a delegate going from view controller to model responsible for game play, adjusting my game logic, and trying viewdidload and viewwillappear. I'm running out of ideas.
Here are samples of pertinent code:
Game View Controller
import UIKit
import Firebase
class GameController: UIViewController, BrainDelegate, UITextFieldDelegate {
#IBOutlet weak var dateUsername: UILabel!
#IBOutlet weak var questionText: UILabel!
#IBOutlet weak var scoreText: UILabel!
#IBOutlet weak var answerOne: UITextField!
var userListOne: [String] = []
#IBOutlet weak var answerTwo: UITextField!
#IBOutlet weak var answerThree: UITextField!
#IBOutlet weak var answerFour: UITextField!
#IBOutlet weak var enterOne: UIButton!
#IBOutlet weak var enterTwo: UIButton!
#IBOutlet weak var enterThree: UIButton!
#IBOutlet weak var enterFour: UIButton!
#IBOutlet weak var feedbackText: UILabel!
#IBAction func logoutPressed(_ sender: UIBarButtonItem) {
do {
try Auth.auth().signOut()
navigationController?.popToRootViewController(animated: true)
} catch let signOutError as NSError {
print ("Error signing out: %#", signOutError)
}
}
let db = Firestore.firestore()
var questions = [Question]()
var Brain = Brain()
var delegate: brainDelegate?
//variables for delegate with json data
var questioner : String?
var dater : String?
var a1 : String?
var a2 : String?
var a3 : String?
var a4 : String?
//For game play
var answer1: String?
var answer2: String?
var answer3: String?
var answer4: String?
var puzzlesCompleted = "0"
func didUpdateBrain(narratives: [Question]) {
self.questions = narratives
}
func didFailWithError(error: Error) {
print(error)
}
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
minketBrain.delegate = self
answerOne.delegate = self
answerTwo.delegate = self
answerThree.delegate = self
answerFour.delegate = self
if let localData = minketBrain.readLocalJSONFile(forName: K.minketClues) {
minketBrain.parseJSON(jsonData: localData)
}
//Transfer data from Profile Controller
self.questionText.text = questioner
self.dateUsername.text = dater
self.answer1 = a1
self.answer2 = a2
self.answer3 = a3
self.answer4 = a4
}
override func viewWillAppear(_ animated: Bool) {
view.reloadInputViews()
answerOne.text = userListOne.last
}
//MARK: - Button Logic
#IBAction func enterPressed(_ sender: UIButton) {
enterPressedOne()
allRight()
}
//Other buttons replicate the same code above
//MARK: - Correct Answer Logic
func allRight(){
if answerOne.backgroundColor == UIColor.green && answerTwo.backgroundColor == UIColor.green && answerThree.backgroundColor == UIColor.green && answerFour.backgroundColor == UIColor.green {
feedbackText.text = K.congratsText
puzzlesCompleted = "1"
if let allAnswer = scoreText.text, let userName = Auth.auth().currentUser?.email{
db.collection(K.FStore.collectionName).addDocument(data: [K.FStore.userName:userName, K.FStore.clueDate:dateUsername.text!, K.FStore.totalPoints:allAnswer, K.FStore.completionField:puzzlesCompleted]) { (error) in
if let e = error{
print("There was an error in data collection to Firestore \(e)")
}else{
print("Successfully saved data")
}
}
}
}
}
//MARK: - Update UI-Each Question
func enterPressedOne(){
if let item = answerOne.text, item.isEmpty == true { // need to make sure we have something here
userListOne.append(item) // store it in our data holder
print(userListOne)
}
if answerOne.text == self.answer1!.lowercased(){
answerOne.backgroundColor = UIColor.green
enterOne.isHidden = true
answerOne.isEnabled = false
}else{
answerOne.backgroundColor = UIColor.red
}
}
}
Unwind segue function in my profile controller
#IBAction func unwindToDestinationViewController (sender: UIStoryboardSegue){
print("Unwind")
}

Cannot use instance member 'userCard1' within property initializer; property initializers run before 'self' is available error [duplicate]

This question already has answers here:
How to initialize properties that depend on each other
(4 answers)
Closed 2 years ago.
Trying to make a simple Blackjack app to get comfortable with using Xcode. I've never coded in Swift before and have a little experience in C++. Having an error I don't know how to fix. I'm having trouble applying other answers to similar questions to my situation.
I'm not totally sure what's causing the problem, let alone how to fix it :)
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
}
var balance = 500
let suits = ["h","d","c","s"]
//user card declarations
#IBOutlet weak var userCard1: UIImageView!
#IBOutlet weak var userCard2: UIImageView!
#IBOutlet weak var userCard3: UIImageView!
#IBOutlet weak var userCard4: UIImageView!
#IBOutlet weak var userCard5: UIImageView!
#IBOutlet weak var userCard6: UIImageView!
#IBOutlet weak var userCard7: UIImageView!
#IBOutlet weak var userCard8: UIImageView!
#IBOutlet weak var userCard9: UIImageView!
#IBOutlet weak var userCard10: UIImageView!
//dealer card declarations
#IBOutlet weak var dealerCard1: UIImageView!
#IBOutlet weak var dealerCard2: UIImageView!
#IBOutlet weak var dealerCard3: UIImageView!
#IBOutlet weak var dealerCard4: UIImageView!
#IBOutlet weak var dealerCard5: UIImageView!
var win = false
var bet = 0
//bet label
#IBOutlet weak var betLabel: UILabel!
//bet slider
#IBAction func betSlider(_ sender: UISlider) {
betLabel.text = String(Int(sender.value))
}
#IBOutlet weak var betSliderValue: UISlider!
var userCardSlot = 3
var dealerCardSlot = 3
var userTotal = 0
var dealerTotal = 0
//user cards displayed
var userCardArray = [userCard1, userCard2, userCard3, userCard4, userCard5, userCard6, userCard7, userCard8, userCard9, userCard10]
//dealer cards displayed
var dealerCardArray = [dealerCard1, dealerCard2, dealerCard3, dealerCard4, dealerCard5]
//hit button
#IBAction func hitTapped(_ sender: Any) {
var cardNum = Int.random(in: 2...14)
var cardSuit = Int(arc4random()) % 4
userCardArray[userCardSlot].image = UIImage(named: "\(cardSuit)card\(cardNum)")
}
//stand button
#IBAction func standTapped(_ sender: Any) {
for userTotal in userCardArray.reversed() {
userTotal += cardNum
}
for dealerTotal in dealerCardArray {
dealerTotal += cardNum
}
while dealerTotal < 17 {
dealerCardSlot += 1
dealerCardArray[dealerCardSlot].image = UIImage(named: "\(cardSuit)card\(cardNum)")
}
if dealerTotal <= userTotal {
win = true
} else {
win = false
}
}
#IBAction func newRoundTapped(_ sender: Any) {
bet = Int(betSliderValue.value)
userCardArray[0].image = UIImage(named: "\(cardSuit)card\(cardNum)")
userCardArray[1].image = UIImage(named: "\(cardSuit)card\(cardNum)")
dealerCardArray[0].image = UIImage(named: "\(cardSuit)card\(cardNum)")
dealerCardArray[0].image = UIImage(named: "Red_back.jpg")
//prompt for hit or stand
if win == true {
balance += (bet * 2)
} else {
balance -= bet
}
}
}
Any help's appreciated!
You generally cannot use one property to initialize another outside of init, because when you do:
var b = a + 1
the compiler implicitly does:
var b = self.a + 1
but self is not yet available; it's only available during the init.
The only exception is a lazy property initializer:
lazy var b: Int = self.a + 1
In your case, you can move the initialization into init:
var userCardArray: [UIImageView]
init() {
self.userCardArray = [userCard1, userCard2, ... ]
}

How to set a timer to enable/disable buttons

I got an issue.
I want to set a timer that could disable the 6 large buttons of my ViewController2.
For example : Until the timer reach 100, it's not possible to click on the buttons Clue1Button,Clue2Button,Clue3Button,Clue4Button,Clue5Button,Clue6Button
Until the timer reach 200, it's not possible to click on the buttons 2,3,4,5,6 ...
How should I do it ? I tried several times, but I failed each time. Thanks for your help
Code of my ViewController2 :
// ViewController2.swift
// PROJET X
//
// Created by Alexis Decloedt on 22/12/2019.
// Copyright © 2019 Alexis Decloedt. All rights reserved.
//
import UIKit
class ViewController2: UIViewController {
#IBOutlet weak var Clue1Button: UIButton!
#IBOutlet weak var Clue2Button: UIButton!
#IBOutlet weak var Clue3Button: UIButton!
#IBOutlet weak var Clue4Button: UIButton!
#IBOutlet weak var Clue5Button: UIButton!
#IBOutlet weak var Clue6Button: UIButton!
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
}
#IBAction func ChestButton(_ sender: Any) {
dismiss(animated: false, completion: nil)
}
}
//
// ViewController2.swift
// PROJET X
//
// Created by Alexis Decloedt on 22/12/2019.
// Copyright © 2019 Alexis Decloedt. All rights reserved.
//
import UIKit
var currentCount : Int?
var maxCount : Int?
var mytimer : Timer?
let ValeurStock = "ValeurStock"
class ViewController2: UIViewController {
#IBOutlet weak var Clue1Button: UIButton!
#IBOutlet weak var Clue2Button: UIButton!
#IBOutlet weak var Clue3Button: UIButton!
#IBOutlet weak var Clue4Button: UIButton!
#IBOutlet weak var Clue5Button: UIButton!
#IBOutlet weak var Clue6Button: UIButton!
override func viewDidLoad() {
super.viewDidLoad()
currentCount = 0
self.mytimer = Timer.scheduledTimer(timeInterval: 2, target: self, selector: #selector(increase), userInfo: nil, repeats: true)
}
#IBAction func ChestButton(_ sender: Any) {
dismiss(animated: false, completion: nil)
}
func increase() {
currentCount! += 1
}
func buttonStatus() {
if currentCount ?? <#default value#> >= 100 {
//I'm stuck ?? How to continue ?
}
}
}
Try to make my button disable/enable
What you may want to do is:
//Add variable that will count how many times Timer was repeated.
var timerCount = 0
//Create timer
Timer.scheduledTimer(withTimeInterval: 100, repeats: true) { t in
//After first 100 sec passed, timer will get triggered and enable the buttons you want.
button1.isEnabled = true
button2.isEnabled = true
//After another 100 passed, timer will enable other buttons
if timerCount == 1 {
button3.isEnabled = true
button4.isEnabled = true
t.invalidate()
}
//Adds 1 to timer count
timerCount += 1
}

UIActivityIndicator shows for a split second

I am trying to show an spinning activity indicator for my app when the user taps on a button before they are presented with the next view - it kind of works, I see it for a split second
#IBOutlet weak var myActivityIndicator: UIActivityIndicatorView!
#IBOutlet weak var eventsbtn: UIButton!
#IBOutlet weak var pubsbtn: UIButton!
override func viewWillAppear(animated: Bool) {
myActivityIndicator.stopAnimating()
myActivityIndicator.hidden = true
}
override func viewDidLoad() {
super.viewDidLoad()
eventsbtn.layer.cornerRadius = 8
pubsbtn.layer.cornerRadius = 8
}
#IBAction func getEvents(sender: AnyObject) {
myActivityIndicator.hidden = false
myActivityIndicator.startAnimating()
}
Refactor your code. You don't need to stop the activity indicator in viewWillAppear. You can hide it in viewDidLoad. Here's the code:
#IBOutlet weak var myActivityIndicator: UIActivityIndicatorView!
#IBOutlet weak var eventsbtn: UIButton!
#IBOutlet weak var pubsbtn: UIButton!
override func viewDidLoad() {
super.viewDidLoad()
eventsbtn.layer.cornerRadius = 8
pubsbtn.layer.cornerRadius = 8
myActivityIndicator.hidden = true
}
#IBAction func getEvents(sender: AnyObject) {
myActivityIndicator.hidden = false
myActivityIndicator.startAnimating()
}
Make sure that the IBOutlet for the activity indicator and IBAction for getting events are correctly connected in Interface Builder.
I changed it and it doesn't work, until I go back in the navigation
#IBOutlet weak var myActivityIndicator: UIActivityIndicatorView!
#IBOutlet weak var eventsbtn: UIButton!
#IBOutlet weak var pubsbtn: UIButton!
override func viewDidLoad() {
super.viewDidLoad()
myActivityIndicator.stopAnimating()
myActivityIndicator.hidden = true
eventsbtn.layer.cornerRadius = 8
pubsbtn.layer.cornerRadius = 8
}
#IBAction func getEvents(sender: AnyObject) {
myActivityIndicator.hidden = false
myActivityIndicator.startAnimating()
}
viewDidAppear is probably a more appropriate place to stop the animation and hide the spinner.

Error - 'ViewController' does not have a member named 'seconds'

I am making an app where a textfield input is shown on a label for the amount of time (in seconds) indicated on an other textfield. My app only runs when var seconds is set to an integer and not to the textfield input. When I set var seconds to the textfield input, I get the following error on the indicated lines of code: 'ViewController' does not have a member named 'seconds' Can anyone help? Thanks.
Here is all of my code, the lines of code with the error have //Error beside them:
class ViewController: UIViewController {
#IBOutlet weak var chronometre: UILabel!
#IBOutlet weak var prochainpointLabel: UILabel!
#IBOutlet weak var pointactuelLabel: UILabel!
#IBOutlet weak var point1Textfield: UITextField!
#IBOutlet weak var point1tempsTextfield: UITextField!
#IBOutlet weak var point2Textfield: UITextField!
#IBOutlet weak var point2tempsTextfield: UITextField!
var timer = NSTimer()
var seconds = point1tempsTextfield.text.toInt()
func subtractTime(dt:NSTimer){
seconds-- //Error
chronometre.text = "\(seconds)" //Error
if(seconds == 0) { //Error
seconds = point2tempsTextfield.text.toInt()
pointactuelLabel.text = point2Textfield.text
prochainpointLabel.text = nil
}
}
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
#IBAction func presenterButton(sender: AnyObject) {
pointactuelLabel.text = point1Textfield.text
prochainpointLabel.text = point2Textfield.text
chronometre.text = "\(seconds)" //Error
timer = NSTimer.scheduledTimerWithTimeInterval(1.0, target: self, selector: ("subtractTime:"), userInfo: nil, repeats: true)
}
}
Thank you for your help, I am very new to coding and really appreciate it!
Forget about using a timer to calculate time. You should use NSTimeInterval between two dates to measure elapsed time.
ElapsedTime
extension NSTimeInterval {
var time:String {
return String(format:"%02d:%02d", Int((self/60.0)%60), Int((self) % 60 ))
}
}
var startTime:NSTimeInterval = 0
var elapsedTime:NSTimeInterval = 0
startTime = NSDate().timeIntervalSinceReferenceDate // 446644854.4675
sleep(3) //
elapsedTime = NSDate().timeIntervalSinceReferenceDate - startTime // 3.005680024623871
println(elapsedTime.time) "00:03"
// applying this concept to your code would look like this:
class ViewController: UIViewController {
#IBOutlet weak var chronometre: UILabel!
#IBOutlet weak var prochainpointLabel: UILabel!
#IBOutlet weak var pointactuelLabel: UILabel!
#IBOutlet weak var point1Textfield: UITextField!
#IBOutlet weak var point1tempsTextfield: UITextField!
#IBOutlet weak var point2Textfield: UITextField!
#IBOutlet weak var point2tempsTextfield: UITextField!
var timer = NSTimer()
var startTime:NSTimeInterval = 0
func updateTime(){
chronometre.text = (NSDate().timeIntervalSinceReferenceDate - startTime).time
}
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
#IBAction func presenterButton(sender: AnyObject) {
pointactuelLabel.text = point1Textfield.text
prochainpointLabel.text = point2Textfield.text
timer = NSTimer.scheduledTimerWithTimeInterval(1/10, target: self, selector: ("updateTime:"), userInfo: nil, repeats: true)
startTime = NSDate().timeIntervalSinceReferenceDate
}
}

Resources