WatchKit : connect 2 sliders to 1 label - swift

tenSlider is going to change the currentBPM value by 10 and pass its result to bpmLabel. This works fine.
However, I also want the onesSlider update that same label, but instead by +1 or -1.
The problem is that it doesn't check the current value and update that value. Instead it just updates its own value and passes it to the bpmLabel.
Anyone know how to connect the two?
import WatchKit
import Foundation
class InterfaceController: WKInterfaceController {
#IBOutlet var bpmLabel: WKInterfaceLabel!
#IBOutlet var tenSlider: WKInterfaceSlider!
#IBOutlet var onesSlider: WKInterfaceSlider!
var currentBPM = Int()
#IBAction func tenSliderDidChange(value: Int) {
currentBPM = value
updateLabel()
}
#IBAction func onesSliderDidChange(value: Int) {
currentBPM = value
updateLabel()
}
func updateLabel() {
bpmLabel.setText("\(currentBPM)")
}

You're always changing the currentBPM value to the value that is set by the slider. So if you set the ones slider the currentBPM value contains the values for one slider and same thing for tens. Since you can't access the value from sliders directly I suggest going this way:
var ones = Int()
var tens = Int()
var currentBPM: Int {
return tens * 10 + ones
// return tens + ones - depending on how did you set the min, max and step values on the ten slider
}
#IBAction func tenSliderDidChange(value: Int) {
tens = value
updateLabel()
}
#IBAction func onesSliderDidChange(value: Int) {
ones = value
updateLabel()
}
func updateLabel() {
bpmLabel.setText("\(currentBPM)")
}

Related

How do I update a label in a different view controller?

I’m very new to coding. I created a game and there is a scoreLabel in the top corner of GameViewController. I created another label in a different view controller (ShopViewController) called moneyLabel. I want the money label to be equal to the score. I made it so that my score label resets every time you start a new game, but I want my money to stay the same so that I can use the money for purchases in game.
I don’t know how to make it update. I tried: gameViewController = GameViewController() and then using code to update my label but it’s not working. My label isn’t updating at all. It stays at 0.
I think you have to use some model struct where you can add your score or any other data and easily manipulate it:
struct GameData{
var totalScore: Int = 0
var currentGameScore: Int = 0
func invalidateCurrentScore(){
totalScore += currentGameScore
currentGameScore = 0
//call this method when you need to set your current score to 0, and pass all the accumulated points to your total score (f.ex. in the end of the game)
}
//some other data like player's name and etc...
}
You also need to create a delegation protocol for using its method in ShopViewController and returning the game data to GameViewController:
protocol ShopViewControllerDelegate{
func updateGameData(by gameData: GameData)
}
GameViewController with new parts:
class GameViewConroller: UIViewController, ShopViewControllerDelegate{
#IBOutlet weak var scoreLabel: UILabel!
var gameData: GameData!
override func viewDidLoad(){
super.viewDidLoad()
gameData = GameData()
updateScoreLabel()
}
private func updateScoreLabel(){ //call it anyTime when you manipulate the score of current game
scoreLabel.text = "Score: \(gameData.currentGameScore)"
}
func updateGameData(by gameData: GameData){ //This is the delegate's method that ShopViewController needs to trigger when you buy something in the shop
self.gameData = gameData
updateScoreLabel()
}
override func prepare(for segue: UIStoryboardSegue,
sender: Any?){
if let shopViewController = segue.destination as? ShopViewController{
//passing game data to ShopViewController
shopViewController.gameData = self.gameData
shopViewController.delegate = self //!IMPORTANT
}
}
}
And these are some properties and methods that your ShopViewController should have:
class ShopViewController{
#IBOutlet weak var totalScoreLabel: UILabel!
var gameData: GameData!
var delegate: ShopViewControllerDelegate?
override func viewDidLoad(){
super.viewDidLoad()
updateTotalScoreLabel()
}
private func updateTotalScoreLabel(){
totalScoreLabel.text = "Total Score: \(gameData.totalScore + gameData.currentGameScore)"
}
private func purchasingSomething(){
//logic of getting price of an item
gameData.currentGameScore -= price
if gameData.currentGameScore < 0{
gameData.totalScore += gameData.currentGameScore
gameData.currentGameScore = 0
//if your current score is less than 0 after some purchase, your total score decreases and the current score becomes 0
}
updateTotalScoreLabel()
delegate?.updateGameData(by gameData: gameData) //Pass refreshed gameData back to the GameViewController
}
}
Also Swift has static variables, but it's very easy to use. Delegates bring more fun and makes code more pretty.
struct GameData{
static var totalScore: Int = 0
static var currentGameScore: Int = 0
}
Good luck and have fun with the game dev :)

How do I assign Y to X?

I couldn't figure out how to copy value of variable into another variable in Swift, an example code for this in python would be
def assignVariable():
x=1
y=x
return y
RESULT 1
When I did this it doesn't seem to work in Swift. Is there any solution to this or am I doing something wrong?
Edit: problem is at
var originalCount=countDown
it gave me Use of unresolved identifier 'countDown' but when I assign it literally it works. Here's my swift code
import Cocoa
class MainWindow: NSWindowController {
var hitCount = 0
var started:Bool = false
var timer = 10
var colorList: [NSColor] = [ NSColor.black,NSColor.blue,NSColor.brown,NSColor.cyan,NSColor.darkGray,NSColor.gray,NSColor.green,NSColor.lightGray,NSColor.magenta,NSColor.orange,NSColor.purple,NSColor.red,NSColor.white,NSColor.yellow]
#IBOutlet weak var button1: NSButton!
#IBOutlet weak var scrubber1: NSScrubber!
#IBOutlet weak var display: NSTextField!
override func windowDidLoad() {
super.windowDidLoad()
// Implement this method to handle any initialization after your window controller's window has been loaded from its nib file.
}
var countdown=10
var originalCount=countDown
//(countdown,originalCount) = (10,10) //it works if i use this instead
func startGame(){
if(countDown>0 || started==true){
display.stringValue=String(countDown)
countDown-=1
let seconds = 1.0
DispatchQueue.main.asyncAfter(deadline: .now() + seconds) {
self.startGame()
}
}else{
display.stringValue="Done "+String(hitCount)+" Taps in " + String(originalCount) + "Tap to RESET"
started=false
countDown=10;
}
}
#IBAction func labelPress(_ sender: Any) {
display.stringValue="__RESET__"
hitCount=0
countDown=10
started=false
}
#IBAction func buttonPressed(_ sender: Any) {
if started==false{
startGame()
}
button1.bezelColor = colorList[Int.random(in: 0..<colorList.count)]
started=true
button1.title=String(hitCount)
hitCount+=1
}
}
You can't initialise one variable with another at the top level in your class. Looking at your code I don't think that originalCount needs to be a property, move it inside startGame() instead and make it a local variable and also use let since it isn't changing
var countdown=10
func startGame(){
let originalCount = countDown
if(countDown>0 || started==true){
...
}

Bind properties in Swift to NSTextFields

I'm working on a unit converter written in Swift that will automatically display the updated units within the appropriate NSTextFields. For this example, if the user inputs minutes into the minutesField, the secondsField and hoursField should automatically update to display the converted values from the properties. Below is an example of the code in my view controller:
import Cocoa
class ViewController: NSViewController {
#IBOutlet weak var secondsField: NSTextField!
#IBOutlet weak var minutesField: NSTextField!
#IBOutlet weak var hoursField: NSTextField!
var sec: Double = 1
var min: Double = 1
var hr: Double = 1
let conv = [[1, 0.0166666666666667, 0.000277777777777778],
[60, 1, 0.0166666666666667],
[3600, 60, 1]]
func updateTextFields() {
secondsField.stringValue = "\(sec)"
minutesField.stringValue = "\(min)"
hoursField.stringValue = "\(hr)"
}
}
extension ViewController: NSTextFieldDelegate {
override func controlTextDidChange(obj: NSNotification) {
let tag = obj.object?.tag() ?? 0
let text = obj.object?.stringValue ?? "1"
let value = Double(text) ?? 1.0
switch tag {
case 0:
// base unit = seconds
sec = value
min = value * conv[0][1]
hr = value * conv[0][2]
case 1:
// base unit = minutes
sec = value * conv[1][0]
min = value
hr = value * conv[1][2]
case 2:
// base unit = hours
sec = value * conv[2][0]
min = value * conv[2][1]
hr = value
default:
"none"
}
updateTextFields()
}
}
The code above updates the text fields but the active field with the input freezes after the first key stroke. For example, if you try to enter 60 into the seconds field, the next key stroke does not do anything. The number 6.0 appears after the first key stroke (see image below). This is likely due to the function that is called after the properties are updated. The properties are updated based on the tag of the active text field.
Is it possible to have a function that will update all the other text fields other than the currently active field?
Is it possible to have a function that will update all the other text
fields other than the currently active field?
Yes. You can connect all text field to the same action.
First connect all your text fields accordingly to your view controller:
#IBOutlet weak var hourField: NSTextField!
#IBOutlet weak var minuteField: NSTextField!
#IBOutlet weak var secondField: NSTextField!
Second create a single var to represent your time interval. You can also add a setter / getter to store it automatically to USerDefaults:
var timeInterval: TimeInterval {
get {
return UserDefaults.standard.double(forKey: "timeInterval")
}
set {
UserDefaults.standard.set(newValue, forKey: "timeInterval")
}
}
Third create a TimeInterval extension to convert the time from seconds to hour/minute
extension TimeInterval {
var second: Double { return self }
var minute: Double { return self / 60 }
var hour: Double { return self / 3600 }
var hourToMinute: Double { return self * 60 }
var hourToSecond: Double { return self * 3600 }
var minuteToHour: Double { return self / 60 }
var minuteToSecond: Double { return self * 60 }
}
Fourth create the action that will update the other text fields:
#IBAction func timeAction(sender: NSTextField) {
// use guard to convert the field string to Double
guard let time = Double(sender.stringValue) else { return }
// switch the field
switch sender {
case hourField:
// convert / update secondary fields
minuteField.stringValue = time.hourToMinute.description
secondField.stringValue = time.hourToSecond.description
// make it persist through launches
timeInterval = time * 3600
case minuteField:
hourField.stringValue = time.minuteToHour.description
secondField.stringValue = time.minuteToSecond.description
timeInterval = time * 60
default:
hourField.stringValue = time.hour.description
minuteField.stringValue = time.minute.description
timeInterval = time
}
}
Last but not least make sure you load the values next time your view will appear:
override func viewWillAppear() {
hourField.stringValue = timeInterval.hour.description
minuteField.stringValue = timeInterval.minute.description
secondField.stringValue = timeInterval.second.description
}
Sample Project
You need to move the setting of the text fields' values out of viewDidLoad() to a separate method. Call that method from viewDidLoad() and also from a didSet property observer on your seconds property.
You also need to create action methods for when the seconds, minutes, or hours fields are changed. In the action method for the seconds field, set the seconds property to secondsField.floatValue. Similarly for the other two fields. In the NIB/storyboard, connects the text fields' actions to the corresponding action method on the view controller.

Updating a integer as a label in swift

I want to change the number value of a label by pressing a button. I used to get errors saying you can't put a number in a string, so, I did string(variable). It now displays the basic number, 1, but when I click it, it doesn't update!
Here is how I set up the variable:
First, I set up the button, to IBAction. Here is the code inside of it:
#IBOutlet weak var NumberOfExploits: UILabel!
#IBAction func exploiter(sender: AnyObject) {
var hacks = 0
hacks += 1
NumberOfExploits.text = String(hacks)
}
Can someone help be find out how to get it to change numbers?
First:
let is used for constants, these can not be changed.
var is used for variables.
Second:
Doing plus one is done with += 1 or with = myVariable + 1
var myVariable = 1
myVariable += 1
label.text = string(myVariable)
It is important to understand that your variables only live as long as the enclosing class or function is alive. So when you declare a variable, constant inside a function (using var let is a declaration) it will be be gone when the function is complete. A UIViewcontroller is there for as long as you want it to be. So declare things in there that you will need later.
import UIKit
// things that live here are at the "global level"
// this is a viewcontroller. It is a page in your app.
class ViewController: UIViewController {
// things that live here are at the "class level"
var myClassCounter : Int = 0
// button in interfacebuilder that is connected through an outlet.
#IBOutlet weak var myButton: UIButton!
override func viewDidLoad() {
super.viewDidLoad()
// this is a function that gets called when the view is loaded
}
override func viewDidAppear(animated: Bool) {
// this is a function that gets called when the view appeared
}
// button function from interface builder
#IBAction func myButtonIsTouched(sender: AnyObject) {
// this will be destroyed when the function is done
var myFunctionCounter = 0
myFunctionCounter += 1
// this will be stored at class level
myClassCounter += 1
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
}
You can also just do
label.text = "\\(variable)"
which will display the number as string.
Most important declare the variable within the class but outside any function
var variable = 1
then write the IBAction function this way
#IBAction func pressButton(sender : UIButton)
{
label.text = "\(++variable)"
}
The syntax ++variable increments the variable by one.
The syntax "\(v)" creates a string of anything which is string representable

Adding Ints in a UILabel in Swift

I am making an app where there is a football field and when you click on the Score Zone 7 points are added to the UILabel that marks score. But I have only been able to display a 7 once and if I click again the seven appears again; I want it to add 7 more to make a 14.
#IBAction func touchdownMD(sender: AnyObject) {
var pointsMD = Int()
scoreMD.text = "\(pointsMD + 7)"
}
#IBOutlet var scoreSH: UILabel!
When you initialize pointsMD inside of the touchdownMD: function, it starts from 0 whenever the function is called.
In order to fix this, you need to declare it at the class level. For example:
var pointsMD = Int() //initialize pointsMD at the class level
#IBAction func touchdownMD(sender: AnyObject){
pointsMD+=7 //add 7 to pointsMD
scoreMD.text = "\(pointsMD)"
}
That way, pointsMD will not reset whenever touchdownMD: is called, it will instead just increment as needed.
So, here's what your code could look like:
var pointsMD = Int()
#IBAction func touchdownMD(sender: AnyObject) {
pointsMD+=7
scoreMD.text = "\(pointsMD)"
}
#IBOutlet var scoreSH: UILabel!