acessing variables from one class to another in swift - 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
}
}

Related

how to append data to struct on another viewcontroller whenever i click a button and keep the prev data persistent

I have this button whenever I click this button, I want to append new data to a struct on another viewcontroller and show it on tableview and when I go back to add more data the prev data wont gone. In my case, I can only add 1 data, after I go back and add more data, the previous one is gone.
ViewController segue code and storyboard:
override
viewcontroller
confirmviewcontroller code and storyboard:
class ConfirmViewController: UIViewController, UITableViewDelegate, UITableViewDataSource {
struct menu {
let menuImages : String
let menuPrice : Int
}
#IBOutlet weak var totalLbl: UILabel!
#IBOutlet weak var confirmBtn: UIButton!
#IBOutlet weak var cartTable: UITableView!
var data: [menu] = [
**confirmcontroller storyboard**
when you go back to previous controller your VC is removed from navigation controller so the object of ConfirmViewController removed from memory so when you again pushed ConfirmViewController in navigation stack that new object for that class again initialised and at that time array of data is Empty and before pushing you again add one item in data which you are adding while moving your segue. This is why your previous items are removing .SUGGESTED SOLUTION: If you want to hold all items data than you can define another class for Holding Data and that will not be clear from memory and when your ConfirmViewController appears get all list from that class and populate that data
class DataRack : NSObject{
static let sharedManager : DataRack = DataRack()
var itemsData : [menu] = []
}
One more thing when you are done with these items you have to clear it from that DataRack Class
You have option for this
if you want to store data permanently then store into UserDefaults like this.
First screen :---
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if (segue.identifier == "main1btn") {
let vc = segue.destination as! ConfirmViewController
}
if (segue.identifier == "main2btn") {
let vc = segue.destination as! ConfirmViewController
}
if (segue.identifier == "main3btn") {
let vc = segue.destination as! ConfirmViewController
}
var newData = [menu]()
if let data = UserDefaults.standard.object(forKey: "yourKey") as? [menu] {
newData.append(data)
} else {
newData.append(menu(menuImages: "main3",menuPrice: 120000))
}
UserDefaults.standard.setValue(value: newData, forKey: "yourKey")
}
Second Screen :--
class ConfirmViewController: UIViewController, UITableViewDelegate, UITableViewDataSource {
var data = [menu]()
override func viewDidLoad() {
super.viewDidLoad()
if let data = UserDefaults.standard.object(forKey: "yourKey") as? [menu]{
data = data
}
}
}
OR
if you do not want to store data then take
struct menu {
let menuImages : String
let menuPrice : Int
}
and
var data: [menu] = [
]
variable globally
removeAll while you not need data

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: display a random array index every button click

I have a swift class that reads lines from a text document and prints out the first line. After, every time a button is clicked a new line is read out.
What I want is to have a random line printed out the first time, and then a random line printed out after every button click.
Here's what I have so far:
import Foundation
import UIKit
class InfoController: UIViewController {
// MARK: Properties
#IBOutlet weak var difficultylevel: UILabel!
var i:Int = 0
override func viewDidLoad() {
super.viewDidLoad()
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
func readFile(){
if let path = NSBundle.mainBundle().pathForResource("easymath", ofType: "txt"){
var data = String(contentsOfFile:path, encoding: NSUTF8StringEncoding, error: nil)
if let content = data {
let myStrings = content.componentsSeparatedByCharactersInSet(NSCharacterSet.newlineCharacterSet())
let randomIndex = Int(arc4random_uniform(UInt32(myStrings.count)))
difficultylevel.text = myStrings[randomIndex]
}
}
}
#IBAction func difficultybutton(sender: UIButton) {
difficultylevel.text = // TODO insert random index of "myStrings" array here
}
}
However, I cannot access the myStrings array at the TODO portion inside the button click. Any help on how to set this up?
Variable scope in Swift is limited to the brackets of the function. So to make myStrings available outside of your readFile() function, you need to declare it as a property for the class:
#IBOutlet var difficultyLevel: UILabel? // BTW your IBOutlet should not be weak
var i: Int = 0
var myStrings: [String]?
Since you are going to use the random functionality over and over, we can abstract the function like this
func randomString() -> String? {
if let strings = myStrings {
let randomIndex = Int(arc4random_uniform(UInt32(myStrings.count)))
return strings[randomIndex]
}
return nil
}
then your instantiation will be like this
if let content = data {
myStrings = content.componentsSeparatedByCharactersInSet(NSCharacterSet.newlineCharacterSet())
difficultyLevel.text = randomString()
}
Then, your difficultybutton function will be (with an abstracted random string function)
// Changed the name for better readibility
#IBAction func difficultyButtonTapped(sender: UIButton) {
difficultyLevel.text = randomString()
}
Finally, there isn't any code that calls the readFile function, so you should add it to probably the viewDidLoad function as #CharlesCaldwell points out
override func viewDidLoad() {
super.viewDidLoad()
readFile()
}

How to know which NSCombobox selector calling the Delegate

I have the following code written in SWIFT for OS X App, the code is working fine (NSComboBox are select able only, not editable)
I have these two IBOutlet projNewProjType and projNewRouter, when I change the the selection of either of the NSComboBox, I can see the correct selected Index value and String value but how to check that the returned Index value is from projNewProjType NOT projNewRouter in the comboBoxSelectionDidChange()
import Cocoa
class NewProjectSetup: NSViewController, NSComboBoxDelegate {
let comboxProjValue: [String] = [“No”,”Yes”]
let comboxRouterValue: [String] = ["No","Yes"]
#IBOutlet weak var projNewProjType: NSComboBox!
#IBOutlet weak var projNewRouter: NSComboBox!
#IBAction func btnAddNewProject(sender: AnyObject) {
print(“Add New Button Pressed!”)
}
#IBAction func btnCancel(sender: AnyObject) {
self.dismissViewController(self)
}
override func viewDidLoad() {
super.viewDidLoad()
addComboxValue(comboxProjValue,projNewProjType)
addComboxValue(comboxRouterValue,projNewRouter)
self.projNewProjType.selectItemAtIndex(0)
self.projNewRouter.selectItemAtIndex(0)
self.projNewProjType.delegate = self
self.projNewRouter.delegate = self
}
func comboBoxSelectionDidChange(notification: NSNotification) {
let comboBox: NSComboBox = (notification.object as? NSComboBox)!
print("comboBox comboBox: \(comboBox)")
/* This printed “<NSComboBox: 0x6000001e1a00>”*/
print("comboBox objectValueOfSelectedItem: \(comboBox.objectValueOfSelectedItem)")
/* This printed the correct selected String value */
print("comboBox indexOfSelectedItem: \(comboBox.indexOfSelectedItem)")
/* This printed the correct selected Index value */
}
/* Add value to Combo box */
func addComboxValue(myVal:[String],myObj:AnyObject){
let myValno: Int = myVal.count
for i in 0..<myValno{
myObj.addItemWithObjectValue(myVal[i])
}
}
}
You already know the addresses of your two NSComboBox outlets and you know the address of which NSComboBox caused that notification to trigger, so why not do something like:
func comboBoxSelectionDidChange(notification: NSNotification) {
let comboBox: NSComboBox = (notification.object as? NSComboBox)!
if comboBox == self.projNewProjType
{
print("selection changed via self.projNewProjType")
}
if comboBox == self.projNewRouter
{
print("selection changed via self.projNewRouter")
}
You can set identifiers to your NSComboBoxes in IB. Select your combo box and choose identity inspector and name identifier. Then you are able to do like this:
if comboBox.identifier == "someIdentifier" {
// Do something
}

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