How can I make variables inside an IBAction public to all view controllers? - swift

So I'm trying to make a Chess Time app, where both players have access to a clock and they change the time between bullet(3minutes), Blitz(5minutes), and Rapid(10Minutes). Well in my second view controller SettingsController I made 3 IBActions UIButtons for this.
#IBAction func bulletPressed(_ sender: UIButton) {
var storedTime = bullet
self.delegate?.storedTimeTimer()
self.navigationController?.popViewController(animated: true)
}
#IBAction func blitzPressed(_ sender: UIButton) {
var storedTime = blitz
}
#IBAction func rapidPressed(_ sender: UIButton) {
var storedTime = rapid
}
This is my SettingsController, my whole point is trying to get the storedTime into the first controller. I tried to use a delegate, but I couldn't get it to work.
Here is the full First Controller:
import UIKit
class ChessTimer: UIViewController {
#IBOutlet weak var playerTimer1: UILabel!
#IBOutlet weak var playerTimer2: UILabel!
var timer = Timer()
var time = 10
var isTimerRunning = false
override func viewDidLoad() {
super.viewDidLoad()
if isTimerRunning == false {
runTimer()
}
}
#IBAction func restartButton(_ sender: UIButton) {
}
#IBAction func pausePressed(_ sender: UIButton) {
timer.invalidate()
}
#IBAction func settingsPressed(_ sender: UIButton) {
performSegue(withIdentifier: "goToSettings", sender: self)
}
func runTimer() {
timer = Timer.scheduledTimer(timeInterval: 1, target: self,selector:
(#selector(ChessTimer.updateTimer)),userInfo: nil, repeats: true)
isTimerRunning = true
}
#objc func updateTimer() {
if storedTime! < 1 {
timer.invalidate()
playerTimer1.text = "00:00"
playerTimer2.text = "00:00"
}
else {
storedTime! -= 1
playerTimer1.text = prodTimeString(time: TimeInterval(storedTime)!)
}
}
func prodTimeString(time: TimeInterval) -> String {
let prodMinutes = Int(time) / 60 % 60
let prodSeconds = Int(time) % 60
return String(format: "%02d:%02d", prodMinutes, prodSeconds)
}
#IBAction func playerButton1(_ sender: UIButton) {
}
#IBAction func playerButton2(_ sender: UIButton) {
}
}
extension ChessTimer: SettingsControllerDelegate {
func storedTimeTimer() {
}
}
This is the second full controller
import UIKit
class SettingsController: UIViewController {
var bullet = "03:00"
var blitz = "05:00"
var rapid = "10:00"
var storedTime = 0
var delegate: SettingsControllerDelegate?
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
}
#IBAction func bulletPressed(_ sender: UIButton) {
var storedTime = bullet
self.delegate?.storedTimeTimer()
self.navigationController?.popViewController(animated: true)
}
#IBAction func blitzPressed(_ sender: UIButton) {
var storedTime = blitz
}
#IBAction func rapidPressed(_ sender: UIButton) {
var storedTime = rapid
}
}
protocol SettingsControllerDelegate {
func storedTimeTimer()
}

This can be achieved using a Constants.swift file.
Click File -> New -> File -> Swift File and then name it Constants.swift.
In Constants.swift, declare var storedTime = 0.
Delete var storedTime = 0 from your view controllers, you'll only need it in Constants.swift. (So delete it from SettingsController, etc.)
The storedTime variable will now be public to all view controllers. šŸ‘
Hope this helps someone!

Related

ViewController doesn't pass data on completion

I have 2 ViewControllers.
TimerViewController passes a variable to the EditTimerViewConroller. EditTimerViewConroller edits it and should pass it back, but it looks like code in .completion is not executed.
Any advice how to fix it?
My code is:
TimerViewController
import UIKit
import AVFoundation //play sounds
class TimerViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
}
var player: AVAudioPlayer!
var timer = Timer()
var totalTime = 10.0
var secondsRemaining = 10.0
var secondsPassed = 0.0
let timerStep = 0.1
#IBOutlet weak var timerLabel: UILabel!
#IBOutlet weak var progressBar: UIProgressView!
#IBAction func startPressed(_ sender: UIButton) {
//works fine
}
#IBAction func editTimerButtinPresed(_ sender: UIButton) {
self.performSegue(withIdentifier: "goToEditTimer", sender: self)
let editTimer = EditTimerViewController()
editTimer.completion = { [weak self] duration in
DispatchQueue.main.async {
self?.totalTime = Double(duration!)
print("editTimer completed, totalTime now is \(self?.totalTime)")
}
}
}
func playSound(fileName: String) {
//works fine
}
#objc func updateTimer() {
//works fine
}
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == "goToEditTimer" {
let destinationVC = segue.destination as! EditTimerViewController
destinationVC.duration = Int(totalTime)
print("Pasing duration = \(totalTime) to Edit screen")
}
}
EditTimerViewController
import UIKit
class EditTimerViewController: UIViewController {
let maxDuration = 60
var duration: Int? //timer duraton is passed from Timer
public var completion: ((Int?) -> Void)?
override func viewDidLoad() {
super.viewDidLoad()
durationSlider.minimumValue = 0
durationSlider.maximumValue = Float(maxDuration)
durationSlider.value = Float(duration!)
durationLabel.text = String(duration!) + "s"
}
#IBOutlet weak var durationLabel: UILabel!
#IBOutlet weak var durationSlider: UISlider!
#IBAction func durationSliderChanged(_ sender: UISlider) {
duration = Int(sender.value)
print(duration!)
durationLabel.text = String(duration!) + "s"
}
#IBAction func cancelPressed(_ sender: UIButton) {
print("Cancel pressed, dismissing Edit screen")
self.dismiss(animated: true, completion: nil)
}
#IBAction func savePressed(_ sender: UIButton) {
print("Save pressed, duration is \(duration!)")
completion?(duration!)
self.dismiss(animated: true, completion: nil)
}
}
In the output after pressing Save button I see
Save pressed, duration is 11
but after it there is no sign of
editTimer completed, totalTime now is 11
and timer duration never changes
Change
#IBAction func editTimerButtinPresed(_ sender: UIButton) {
self.performSegue(withIdentifier: "goToEditTimer", sender: self)
let editTimer = EditTimerViewController()
editTimer.completion = { [weak self] duration in
DispatchQueue.main.async {
self?.totalTime = Double(duration!)
print("editTimer completed, totalTime now is \(self?.totalTime)")
}
}
}
To
#IBAction func editTimerButtinPresed(_ sender: UIButton) {
self.performSegue(withIdentifier: "goToEditTimer", sender: self)
}
And move completion inside prepare
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == "goToEditTimer" {
let destinationVC = segue.destination as! EditTimerViewController
destinationVC.duration = Int(totalTime)
print("Pasing duration = \(totalTime) to Edit screen")
destinationVC.completion = { [weak self] duration in
DispatchQueue.main.async {
self?.totalTime = Double(duration!)
print("editTimer completed, totalTime now is \ (self?.totalTime)")
}
}
}
}

Implement a dictionary value into a count down timer

Iā€™m making an appllication quiz in which i want to implement the value of the dictionary to be the intial value of the countdown timer so if the "soft" key is targeted the count down timer starts from 300 instead of 60
import UIKit
class ViewController: UIViewController {
let eggTimes :[String:Int]=["Soft":300,"Medium":420,"Hard":720
]
var count: Int = 60
func startCountDown() {
Timer.scheduledTimer(timeInterval: 1.0, target: self, selector: #selector(updateCounter), userInfo: nil, repeats: true)
}
#objc func updateCounter() {
if count>0 {
count-=1
countDownLabel.text = "\(count)"
print(count)
}
}
#IBOutlet weak var countDownLabel: UILabel!
#IBAction func hardnessSelected(_ sender: UIButton) {
startCountDown()
let hardness=sender.currentTitle!
let result = eggTimes[hardness]!
print(result)
}
} ```
let hardness=sender.currentTitle!
count = eggTimes[hardness]!
startCountDown()
Set count before starting the countdown
#IBAction func hardnessSelected(_ sender: UIButton) {
let hardness = sender.currentTitle!
count = eggTimes[hardness]!
startCountDown()
}
But it's easier to assign tags to the 3 buttons, the three values 300, 420 and 720.
Then you can delete the dictionary and write
#IBAction func hardnessSelected(_ sender: UIButton) {
count = sender.tag
startCountDown()
}

Adding Previous and Next buttons to Audio Player

I'm curious how to add functionality to the next/previous buttons. I have more .mp3 files in my project, but I'm not sure how to set the button functions to click through them. I think I need to set a variable and call the viewdidload() function inside the button function. I am just not 100% certain how to do that.
Noob here, be nice. :)
var player = AVAudioPlayer()
var timer = Timer()
#objc func updateScrubber(){
scrubber.value = Float(player.currentTime)
}
#IBAction func play(_ sender: Any) {
player.play()
timer = Timer.scheduledTimer(timeInterval: 1, target: self, selector: #selector(ViewController.updateScrubber), userInfo: nil, repeats: true)
}
#IBAction func pause(_ sender: Any) {
player.pause()
}
#IBAction func previous(_ sender: Any) {
}
#IBAction func next(_ sender: Any) {
}
#IBAction func sliderMoved(_ sender: Any) {
player.volume = volume.value
}
#IBOutlet weak var volume: UISlider!
#IBAction func scrubberMoved(_ sender: Any) {
player.currentTime = TimeInterval(scrubber.value)
}
#IBOutlet weak var scrubber: UISlider!
override func viewDidLoad() {
super.viewDidLoad()
let audioPath = Bundle.main.path(forResource: "threatofjoy", ofType: "mp3")
do {
try player = AVAudioPlayer(contentsOf: URL(fileURLWithPath: audioPath! ))
scrubber.maximumValue = Float(player.duration)
} catch {
print("Error")
}
I solved this by placing the songs in an array and creating a current song function to call in the button methods.

Trying to pass Doubles from a view to an another but it doesn't work

Hey I'm a newbie to Swift and Xcode and I am trying to make a little app but I have an error and can't fix it.
I'm trying to passe a double from a view to another but it says
Binary operator '+=' cannot be applied to operands of type 'String' and "int"
That's my first view :
#IBOutlet weak var Rned: UILabel!
var ArgentC: Double = 0
override func viewDidLoad() {
super.viewDidLoad()
Rned.text = String(ArgentC)
Rned.backgroundColor = UIColor(patternImage: UIImage(named: "Rectangle2")!)
}
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
let SecondViewController = segue.destination as! SacocheVCp2
SecondViewController.ArgentCV = Rned.text!
}
#IBAction func Reset(_ sender: Any) {
Rned.text = String(0)
ArgentC = 0
}
#IBAction func CashButton(_ sender: Any) {
performSegue(withIdentifier: "segueSac", sender: self)
}
and that is my second view with the error, and the error appears when I want to add numbers to my doubles.
#IBOutlet weak var Rend2Label: UILabel!
var ArgentCV = String()
override func viewDidLoad() {
super.viewDidLoad()
Rend2Label.backgroundColor = UIColor(patternImage: UIImage(named: "Label")!)
Rend2Label.text = ArgentCV
// Do any additional setup after loading the view.
}
#IBAction func CinqEur(_ sender: Any) {
ArgentCV += 5 // <== Here
Rend2Label.text = ArgentCV
}
#IBAction func DixEur(_ sender: Any) {
ArgentCV += 10 // <== Here
}
#IBAction func VingtEur(_ sender: Any) {
ArgentCV += 20 // <== Here
}
#IBAction func CinquanteEur(_ sender: Any) {
ArgentCV += 50 // <== Here
}
Thanks for your time.
You don't have to send it as a String , you can send it as Int
secondViewController.argentCV = Int(rned.text) ?? 0 // ?? to avoid crashes but make sure it doesn't destroy logic
Then inside SacocheVCp2
var argentCV = 0 // 0 is default
Finally
argentCV += 5 // <== Here
rend2Label.text = "\(argentCV)"

Passing Data through 3 view Controllers [Swift 3.0 - Xcode]

Im passing data through 3 VCs, so in the end I want to achieve sending data from the third VC to the first. I send Data from V2 to V3 with a segue and then send it back from V3 to V2 by delegate. Im then trying to send it from V2 to V1 through a segue but I cant seem to collect the data (sent back from V3) in V2 to then send to V1.
The data from V3 doesn't show up in V1, but the code still runs.
Can anyone help?
heres my code from V2 and V3:
V2:
import UIKit
class SecondViewController: UIViewController, thirdDelegate {
var GetBack: String?
var SendForward = [String]()
var Datacollect = [String]()
var Collect = [String]()
let ct = "Conner#2"
let new = "All#2"
#IBOutlet var Hinput: UITextField!
#IBOutlet var Ninput: UITextField!
#IBAction func MAP(_ sender: Any) {
if Hinput.text != ""{
performSegue(withIdentifier: "SegueSearch", sender: self)}
}
#IBAction func Info(_ sender: Any) {
performSegue(withIdentifier: "SegueInfo", sender: self)
}
func DataToPass(ArrayName: [String]) { //function from delegate
Datacollect = ArrayName
print(ArrayName)
}
override func prepare(for segue: UIStoryboardSegue, sender: Any?){
if segue.identifier == "SegueSearch"{
let thirdController = segue.destination as! ThirdViewController
SendForward.append(Hinput.text!)
SendForward.append(ct)
thirdController.height = SendForward
thirdController.delegate = self
} else if segue.identifier == "SegueInfo" {
let firstController = segue.destination as! ViewController
if Datacollect.count != 0{
Collect.append(Datacollect[1])
Collect.append(Datacollect[0])}
Collect.append(Ninput.text!)
Collect.append(new)
firstController.AllData = Collect
}
}
override func viewDidLoad() {
super.viewDidLoad()
print("check",Datacollect)
// Do any additional setup after loading the view.
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
}
Is this the part that isn't working?
func DataToPass(ArrayName: [String]) {
Datacollect = ArrayName
print(ArrayName)
}
V3:
import UIKit
protocol thirdDelegate{
func DataToPass (ArrayName: [String])
}
class ThirdViewController: UIViewController {
var height = [String]()
var SendBack = [String]()
let ko = "Keith#3"
var delegate: thirdDelegate! = nil
#IBOutlet var Houtput: UILabel!
#IBAction func Home(_ sender: Any) {
let StrH = String(height[0])
SendBack.append(ko)
SendBack.append(StrH!)
delegate.DataToPass(ArrayName: SendBack)
}
override func viewDidLoad() {
Houtput.text = height[0]
super.viewDidLoad()
print(height)
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
}
}