Add up integers in different View Controllers - swift

I would like to be able to add up integers from buttons in View Controller 1 to a label in View Controller 2. I´m trying to pass the numbers through a separate swiftFile.
I thought I had the right code for this, but the numbers dont add together in the totalSumLabel.
describing is forced by X-cide. without it I get the error:
"init has been renamed to init(describing)"
inport UIKit
class addPrice: NSNumber {
var allSum: Int = 0
}
The code from View Controller 1:
class ViewController1: UIViewController {
var myTotal: addPrice?
#IBAction func button1(_ sender: UIButton) {
myTotal?.allSum += 190
}
#IBAction func button2(_ sender: UIButton) {
myTotal?.allSum += 240
}
The code from View Controller 2:
class ViewController2: UIViewController {
var myTotal: addPrice?
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
totalSumLabel.text = String (describing: myTotal?.allSum)

I would implement a service like this:
import Foundation
import UIKit
class DataFactory {
var allSum:Int = 0
static let sharedInstance : DataFactory = {
let instance = DataFactory()
return instance
}()
}
And you can get your property value from every ViewController like this:
let allSum = DataFactory.sharedInstance.allSum
Or set your property like this from everywhere:
DataFactory.sharedInstance.allSum += 1
Its not a good idea to save global properties in specific ViewControllers

Related

How to pass a (changing) variable between two view controllers?

I have two view controllers. VC1 & VC2. VC1 is passing a variable which keeps changing & updating every second on VC1, in my case, it is the nearest beacon which is handled by a method in VC1.
VC1 code:
var id: Int = 0 // initializing
// send data to VC2
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
guard let vc2 = segue.destination as? navigationScreenVC else { return }
vc2.id2 = id
}
VC2 code:
var id2: Int = 0
override func viewDidLoad() {
super.viewDidLoad()
print(VC2)
}
It is working where it sends the first value it encounters, but not when the value keeps changing, so I want that to be sent as soon as it triggers a change.
I tried to do didSet{} but it doesn't work that way.
Use a delegate pattern.
In VC2:
protocol VC2Delegate: AnyObject {
var id2: Int { get }
}
class VC2 {
weak var delegate: VC2Delegate?
override func viewDidLoad() {
super.viewDidLoad()
print(delegate?.id2)
}
}
In VC1:
class VC1: UIViewController, VC2Delegate {
...
var id2: Int = 0
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
guard let vc2 = segue.destination as? navigationScreenVC else { return }
vc2.delegate = self
}
...
}
A ViewController should not be managing stuff after it stopped being visible. You should managing this in a separate class and waiting for updates from a delegate, lets say:
protocol BeaconUpdateListener : AnyObject {
func currentBeaconIdWasUpdated(to newValue: Int)
}
class BeaconManager {
struct DelegateWrapper {
weak var delegate : BeaconUpdateListener?
}
static let delegates = [DelegateWrapper]()
static var currentId : Int = -1 {
didSet {
delegates.forEach { (delegate) in
delegate.delegate?.currentBeaconIdWasUpdated(to: currentId)
}
}
}
}
Sample code, missing details. You could make your own or update this one. Now, having that data outside your UI code makes it easier to use from anywhere else, and update that code in the future. This way, you "subscribe" to id updates like this:
BeaconManager.delegates.append(OBJECT_THAT_NEEDS_TO_BE_NOTIFIED)
... update your id like this:
BeaconManager.currentId = 65421687543152
... and wait for updates like this:
class VC2 : ViewController, BeaconUpdateListener {
func currentBeaconIdWasUpdated(to newValue: Int) {
// Do stuff once i receive the update
}
// ...
}

How to set up a NSComboBox using prepare for segue or init?

I am really struggling to pass the contents of one array from a view controller to another to set up the contents of a nscombobox. I have tried everything I can think of, prepare for segue, init; but nothing seems to work.
the program flow is as follows: the user enter a number into a text field and based on it an array with the size of the number is created. Once the user presses a button the next VC appears that has a combo box and inside that combo box those numbers need to appear. All my attempts result in an empty array being passed. Could someone please take a bit of time and help me out. Im sure I'm doing a silly mistake but cannot figure out what.
Code listing below:
Class that take the user input. At this stage I'm trying to pass the contents of the array in the next class as I gave up on prepare for segue because that one crashes because of nil error. Please note that prepare for segue is uncommented in the code listing just for formatting purposes here. Im my program it is commented out as I am using perform segue at the moment.
Any solution would be nice please. Thank you.
import Cocoa
class SetNumberOfFloorsVC: NSViewController {
//MARK: - Properties
#IBOutlet internal weak var declaredNumber: NSTextField!
internal var declaredFloorsArray = [String]()
private var floorValue: Int {
get {
return Int(declaredNumber.stringValue)!
}
}
//MARK: - Actions
override func viewDidLoad() {
super.viewDidLoad()
}
#IBAction private func setNumberOfFloors(_ sender: NSButton) {
if declaredNumber.stringValue.isEmpty {
let screenAlert = NSAlert.init()
screenAlert.messageText = "Please specify the number of floors!"
screenAlert.addButton(withTitle: "Got it!")
screenAlert.runModal()
} else if floorValue == 0 || floorValue < 0 {
let screenAlert = NSAlert.init()
screenAlert.messageText = "Please input a correct number of floors!"
screenAlert.addButton(withTitle: "Got it!")
screenAlert.runModal()
} else {
for i in 0...floorValue - 1 {
declaredFloorsArray.append(String(i))
}
print("\(declaredFloorsArray)")
let declareNumberOfRoomsVC = SetNumberOfRoomsForFloorVC(boxData: declaredFloorsArray)
declareNumberOfRoomsVC.boxData = declaredFloorsArray
performSegue(withIdentifier: "set number of rooms", sender: self)
}
}
override func prepare(for segue: NSStoryboardSegue, sender: Any?) {
if segue.identifier == "set number of rooms" {
if let addRoomsVC = segue.destinationController as? SetNumberOfRoomsForFloorVC {
addRoomsVC.floorBox.addItems(withObjectValues: declaredFloorsArray)
}
}
}
}
this is the class for the next VC with the combo box:
import Cocoa
class SetNumberOfRoomsForFloorVC: NSViewController, NSComboBoxDelegate, NSComboBoxDataSource {
//MARK: - Properties
#IBOutlet internal weak var floorBox: NSComboBox!
#IBOutlet private weak var numberOfRoomsTxtField: NSTextField!
internal var boxData = [String]()
//MARK: - Init
convenience init(boxData: [String]) {
self.init()
self.boxData = boxData
}
//MARK: - Actions
override func viewDidLoad() {
super.viewDidLoad()
floorBox.usesDataSource = true
floorBox.dataSource = self
floorBox.delegate = self
print("\(boxData)")
}
#IBAction private func setRoomsForFloor(_ sender: NSButton) {
}
//MARK: - Delegates
func numberOfItems(in comboBox: NSComboBox) -> Int {
return boxData.count
}
func comboBox(_ comboBox: NSComboBox, objectValueForItemAt index: Int) -> Any? {
return boxData[index]
}
}
First you should remove the following code.
let declareNumberOfRoomsVC = SetNumberOfRoomsForFloorVC(boxData: declaredFloorsArray)
declareNumberOfRoomsVC.boxData = declaredFloorsArray
I assume you think that the viewController you created here is passed to prepareForSegue. However the storyboard instantiates a new viewController for you.
After that you need to set your declaredFloorsArray as the the boxData of the new viewController in prepareForSegue and you should be good to go.

Swift Function Algorithm

when I run this method in my project, the "name" variable is empty
Example :
import UIKit
class userDetail {
static var name : String?
}
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
}
#IBAction func OK(sender: UIButton){
getUserDetail()
print(userDetail.name)
// The first click is nil, the second click is print "test". How can I solve this problem?
}
func getUserDetail() {
userDetail.name = "test"
}
}
You have to instantiate it, as most of the comments suggest.
You need to do:
var userInfo = userDetail()
userInfo.name = "Test"
print(userInfo.name!)
As others suggested, you need to make class names (userDetail) capital. This is because class names start with class names. (UserDetail)

acessing variables from one class to another in swift

In the app the user types in infomations as integers into two different textfields. After a action button click the user now access two other textfields which the user again types data as integers. Now after a click on a button I want a label's text to show this typed in information from the two situations earlier
However in my code, I can't access my variables (the information from the user input) because this label's text is in a new class and the user input variables are stored in two other classes).
How can I access these variables in my new class where my label is?
An example of my code:
#IBOutlet var nextStagetwo: UILabel!
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
}
#IBAction func check(sender: AnyObject) {
var strValue = boxShots.text
var floatValue = Double((strValue as! NSString).integerValue)
var strValue2 = boxMakes.text
var floatValue2 = Double((strValue2 as! NSString).integerValue)
var stage = "stage 2"
var procent = floatValue2 / floatValue * 100
enter code here
I now want to access my variable procent in this class:
class stagethree: UIViewController {
#IBOutlet var stats: UILabel!
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
}
#IBAction func check(sender: AnyObject) {
// this is where I want to write: stats.text = "\(procent)"
// however I can't, because it doesn't register the variable "procent" because it is in another class.
You can either make a global store that stores the values for you
struct Store {
static var valueOne:Int?
}
and then in your view controllers you can set those values
Store.valueOne = 1
Other option would be to send those integers to the next view controller in your
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if let destinationController = segue.destinationViewController as? SecondController {
destinationController.valueOne = valueOne
}
}

variable cannot be modified in another class

am trying to modify a variable in another class, but it doesn't change.
class ViewController: UIViewController {
var t = 1
override func viewDidLoad() {
super.viewDidLoad()
t = 9
var pp = action().test()
println(pp) // got “2” here
}
the above should print "10" , but it shows "2".
another swift file:
class action {
var k = ViewController().t
func test()->Int{
k++
return k
}
}
Anything I made wrong?
Thnaks.
When you have a class with properties, and create an instance of that class, properties are bound to the class instance and not the class type. So if you create 2 instances of the same class their properties are independent, so if you change a property in one instance, that won't affect the same property in the other instance.
Note: by convention, in swift type names always start in uppercase, so I have renamed action to Action in my code.
Your code isn't working as expected because in the Action class you are creating a new instance of ViewController:
var k = ViewController().t
which has no relationship with the instance used to instantiate Action - so the new instance will have its t property set to 1.
The correct way to fix it is to pass the view controller instance to Action, and let it work on that instance.
class ViewController: UIViewController {
var t = 1
override func viewDidLoad() {
super.viewDidLoad()
t = 9
var action = Action(viewController: self)
var pp = action.test()
println(pp) // got “2” here
}
}
class Action {
var k: Int
init(viewController: ViewController) {
self.k = viewController.t
}
func test()->Int{
k++
return k
}
}
The above code should give an indication of what's wrong with your code, but it can be written in a better way. Action doesn't really need the ViewController instance, it just needs an integer passed in to its initializer, so a better way to achieve the same result is by modifying the code as follows:
class ViewController: UIViewController {
var t = 1
override func viewDidLoad() {
super.viewDidLoad()
t = 9
var action = Action(t: self.t)
var pp = action.test()
println(pp) // got “2” here
}
}
class Action {
var k: Int
init(t: Int) {
self.k = t
}
func test()->Int{
k++
return k
}
}