This question already has answers here:
Sending Variables with a Segue
(3 answers)
Passing data between view controllers
(45 answers)
Closed 4 years ago.
I tried following this guide that used string value but it wasn't that helpful. I'm working on an app that has 8 buttons, each will be assigned with a number representing seconds converted to minutes in CountdownVC. I'm trying to pass the Int value when I tap a button and assign the value to var seconds = 0 in CountdownVC.
When pressing the button in the MainVC:
#IBAction func oneMinuteBtnPressed(_ sender: Any) {
let vc = CountdownVC()
vc.seconds = 60
performSegue(withIdentifier: "toCountdownVC", sender: self)
}
I want to pass the assigned value to the CountdownVC's making it var seconds = 60:
import UIKit
class CountdownVC: UIViewController {
#IBOutlet weak var countdownLbl: UILabel!
#IBOutlet weak var startBtn: UIButton!
#IBOutlet weak var pauseBtn: UIButton!
#IBOutlet weak var resetBtn: UIButton!
// Variables
var seconds = 0 // This variable will hold the starting value of seconds. It could be any amount over 0
var timer = Timer()
var isTimerRunning = false // This will be used to make sure the only one time is created at a time.
var resumeTapped = false
override func viewDidLoad() {
super.viewDidLoad()
pauseBtn.isEnabled = false
}
func runTimer() {
timer = Timer.scheduledTimer(timeInterval: 1, target: self, selector: (#selector(CountdownVC.updateTimer)), userInfo: nil, repeats: true)
isTimerRunning = true
pauseBtn.isEnabled = true
}
#objc func updateTimer(){
if seconds < 1 {
timer.invalidate()
//TODO: Send alert to indicate "time is up!"
} else {
seconds -= 1 //This will decrement(count down) the seconds.
countdownLbl.text = timeString(time: TimeInterval(seconds)) //This will update the label
}
}
func timeString(time: TimeInterval) -> String {
let hours = Int(time) / 3600
let minutes = Int(time) / 60 % 60
let seconds = Int(time) % 60
return String(format: "%02i:%02i:%02i", hours, minutes, seconds)
}
What I have above doesn't seem to work except for the segue part. Any help would be appreciated.
As Quoc Nguyen pointed it out, you are assigning a value to a controller that will never be used.
When you call performSegue, this will instantiate a different vc from the one you have created.
If you want to pass something to the vc that is created by your storyboard you need to use something like this:
#IBAction func oneMinuteBtnPressed(_ sender: Any) {
performSegue(withIdentifier: "toCountdownVC", sender: self)
}
// This function is called before the segue
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
// get a reference to the your view controller
if let nextViewController = segue.destination as? CountdownVC {
nextViewController.seconds = 60
}
}
Related
class ViewController: UIViewController {
let eggTimes = ["Soft": 5, "Medium": 7, "Hard" : 12]
#IBOutlet weak var eggCountdown2: UILabel!
#IBOutlet weak var eggCountDown: UILabel!
#IBOutlet weak var eggCountdown3: UILabel!
var count1 = 7
var count2 = 5
var count3 = 12
override func viewDidLoad() {
super.viewDidLoad()
var timer = Timer.scheduledTimer(timeInterval: 0.2, target: self, selector: #selector(UIMenuController.update), userInfo: nil, repeats: true)
}
#objc func update() {
switch UILabel() {
case eggCountDown:
print("\(count1) seconds to get your medium egg")
count1 -= 1
case eggCountdown2 :
print("\(count2) seconds to get your soft egg")
count2 -= 1
case eggCountdown3 :
print("\(count3) seconds to get your fucking hard egg")
count3 -= 1
default:
print ("Error")
}
}
#IBAction func hardnessSelected(_ sender: UIButton) {
let hardness = sender.currentTitle!
print(eggTimes [hardness]!)
}
}
I am getting "Error" countdowns in my EggTimer code. It's supposed to be counting down the time each egg takes. I have tried multiple ways to tackle this but always ended with up this. Also I have been scraping Apple documentation for the same but still cannot find the relevant answer.
Screen shot:
Rather than switching on an unrelated label – which cannot work – create a property for the hardness
var hardness = ""
and one counter is sufficient as you apparently not going to run two timers simultaneously.
var counter = 0
and assign both values in hardnessSelected
#IBAction func hardnessSelected(_ sender: UIButton) {
self.hardness = sender.currentTitle!
self.counter = eggtimes[hardness]!
print(counter)
}
Then switch this way
#objc func update() {
switch hardness {
case "Medium":
print("\(count1) seconds to get your medium egg")
counter -= 1
case "Soft" :
print("\(count2) seconds to get your soft egg")
counter -= 1
case "Hard" :
print("\(count3) seconds to get your fucking hard egg")
counter -= 1
default:
print ("Error")
}
}
And you need to check when the countdown ends and to start the timer in the IBAction. And to avoid bad cooking experience set the repeat interval to 60 (one minute) or multiply the egg times by 300.
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.
I have a label (in my secondVC) which is displaying a segued Double from the firstVC. In the secondVCs viewDidLoad I am printing the passedDouble and it is printing the correct amount, so I know my Double is being segued correctly. My UILabel is in the secondVC and only shows an amount if the passedDouble = 0.0.
SecondViewController:
#IBOutlet weak var totalLabel: UILabel!
var passedDouble = 0.0
override func viewDidLoad() {
super.viewDidLoad()
print("testing for a value \(passedDouble)")
totalLabel.text = String("\(passedDouble)")
}
If the passed value is 12.2 for example, it prints this
testing for a value 12.2
But the label completely disappears from view.
If the passed value is 0.0 however, it prints
testing for a value 0.0
and the label shows 0.0
In the storyboard I have left the labels standard text as Label. So, I know the label is connected properly as it's text changes IF the value is nil.
EDIT: Code for the firstVC where I am assigning the value
var totalPrice: Double = Double()
#IBAction func basketAction(_ sender: UIButton) {
for cost in priceDictionaryToBeSent {
totalPrice += Double(cost)!
}
performSegue(withIdentifier: "basket", sender: self)
}
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == "basket" {
if let basketVC = segue.destination as? BasketViewController {
basketVC.passedDouble = totalPrice
//This is sending the correct price
}
}
}
My best guess is that in prepare(for:sender:) the basketVC's view is already loaded, so its viewDidLoad got called before you are setting basketVC.passedDouble = totalPrice.
I would rather use setter to update the label everytime the passedDouble gets updated. Change the BasketViewController code to this:
#IBOutlet weak var totalLabel: UILabel!
var passedDouble = 0.0 {
didSet {
self.totalLabel?.text = "\(passedDouble)"
}
}
override func viewDidLoad() {
super.viewDidLoad()
// no need to set totalLabel.text here
}
Thank you to Milan Nosáľ for saying the view could've already loaded, indeed it had, so I moved the code from viewDidLoad in my BasketViewController to viewDidAppear as seen below:
override func viewDidAppear(_ animated: true) {
super.viewDidAppear(true)
print("testing for total price £\(passedDouble)")
totalLabel.text = "Total price £\(passedDouble)"
}
This question already has answers here:
NSTimer - how to delay in Swift
(4 answers)
Closed 5 years ago.
I have a label that gets hidden when a button is pressed. After a certain time period like 60 secs I want the label to reappear. I'd assume I do that in viewDidAppear, How would i do that?
#IBOutlet weak var myLabel: UILabel!
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
//after 60 secs myLabel should reappear
//self.myLabel.isHidden = false
}
#IBAction func buttonTapped(_ sender: UIButton){
self.myLabel.isHidden = true
}
#IBAction func buttonTapped(_ sender: UIButton){
self.myLabel.isHidden = true
DispatchQueue.main.asyncAfter(deadline: .now() + 60) {
self.myLabel.isHidden = false
}
}
You can do this by scheduling a timer:
class ViewController: UIViewController {
#IBOutlet weak var myLabel: UILabel!
#IBAction func buttonTapped(sender: UIButton) {
if !myLabel.isHidden {
myLabel.isHidden = true
Timer.scheduledTimer(timeInterval: 15.0, target: self, selector: #selector(showLabel), userInfo: nil, repeats: false)
}
}
func showLabel() {
myLabel.isHidden = false
}
}
I'm trying to write simple clicker but I have some problem, on "StartViewController" I have func value() it add per sec 1 + click 1 + last save value and I have shopViewController on the shopViewController I have button when I press it it must give +1(every time) to click but how can I access to current value from func value()? When I try get current value I get nil
func value() -> Float {
let endValue = appPerSec + valueToLoad + click
valueToSave = endValue
valueLable.text = "\(endValue)"
return valueToSave
}
// shopViewController
var StartView:StartViewController!
var currentValue:Float! = 0.0
#IBAction func testAdd(_ sender: Any) {
currentValue = StartView.value // here I get NIL
print(currentValue)
}
i did not UnderStand your question but i can give solution in parts for the terms i can read, or please improve your question so that i can understand exactly what you are looking for.
meanwhile i'll just give some concepts that i think you are looking for, if not useful please edit your question before rating not useful :
to make a timer you can use
#IBOutlet weak var timeInTimer: UILabel!
var timer = Timer()
#IBAction func buttonPressed(_ sender: Any) //to stop the timer
{
timer.invalidate()
}
#IBAction func playButtonPressed(_ sender: Any) //to start the timer
{
timer = Timer.scheduledTimer(timeInterval: 1, target: self, selector: #selector(ViewController.processTimer), userInfo: nil, repeats: true)
}
To pass data from one view to other view :
let anyObjectName = storyboard?.instantiateViewController(withIdentifier: "IdentifierOfSecondViewController") as! IdentifierOfSecondViewController
anyObjectName.userName = userName //where username is a variable in second view
You can use Delegate and Protocols. Above your shopView add:
protocol ShopProtocol{
func updateCount();
}
In your shopView add:
var delegateShop:ShopProtocol?
And when you change that variable, go to:
delegateShop.updateCount()
In your main view controller, when you present this shopViewController (before presenting it), add:
shopController.delegateShop = self
And change your ViewController definition to
class ...: UIViewController, ..., ShopProtocol{
And, of course, create in that view controller:
func updateCount(){
//do Stuff
}