Passing an integer value through view controllers with an addition and subtraction counter [duplicate] - swift

This question already has answers here:
Passing data between view controllers
(45 answers)
Closed 2 years ago.
I am working on a Magic the Gathering Counter app. For my app, I want to click twentyLife(), thirtyLife(), or fourtyLife() to change the value of a variable in another view controller (i.e. FifthViewController.)
Second view controller code:
import UIKit
class SecondViewController: UIViewController {
var vcFive = FifthViewController()
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
}
#IBAction func twentyLife() {
vcFive.lifePoints.text = String(20)
}
#IBAction func thirtyLife() {
vcFive.lifePoints.text = String(20)
}
#IBAction func fortyLife() {
vcFive.lifePoints.text = String(20)
}
I try and call out the fifthViewController as a variable to change my life points text but it does not work.
Here is my code for the fifthViewController:
import UIKit
class FifthViewController: UIViewController {
#IBOutlet weak var lifePoints: UILabel!
var counter = 0
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
}
#IBAction func lifeUp() {
counter += 1
lifePoints.text = String(counter)
}
#IBAction func lifeDown() {
counter -= 1
lifePoints.text = String(counter)
}
Any help would be appreciated. This is my first app I have been trying to work on from scratch

You should create an instance of your FifthViewController on your SecondViewController, and a variable on your FifthViewController in which you can save the data passed. Like this:
SecondViewController
import UIKit
class SecondViewController: UIViewController {
let fifthVC = self.storyboard?.instantiateViewController(withIdentifier: "fifthVC") as? FifthViewController
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
}
#IBAction func twentyLife() {
fifthVC.lifePointsInt = 20
}
#IBAction func thirtyLife() {
fifthVC.lifePointsInt = 30
}
#IBAction func fortyLife() {
fifthVC.lifePointsInt = 50
}
}
FifthViewController
import UIKit
class FifthViewController: UIViewController {
var lifePointsInt = Int()
#IBOutlet weak var lifePoints: UILabel!
override func viewDidLoad() {
super.viewDidLoad()
lifePoints.text = "\(lifePointsInt)"
}
#IBAction func lifeUp() {
lifePoints.text = "\(lifePointsInt + 1)"
}
#IBAction func lifeDown() {
lifePoints.text = "\(lifePointsInt - 1)"
}
}
Remember to type in your Storyboard ID in your storyboard for your FifthViewController as "fifthVC" If your pass to your FifthViewController after selecting your Life Count in your SecondViewController you could add self.navigationController?.pushViewController(fifthVC!, animated: true) at the end of each function.

Related

How to set NSSlider value in a NSToolbar - Swift Cocoa + Storyboard

I am quite new to Swift programming and I am trying to set a slider min, max and value in a NSToolbar. As an hypothetical exemple, I have a list of client and I want to use the slider in the toolbar to select a client data page. I will firt to load the client database in the NSViewController and count the number of client. Than I would like to set the slider in the toolbar minvalue to 1 and maxvalue to the number of client. I understand how to send slider values from the Windowcontroller to the ViewController but I did not found how to do the inverse , how to send data from the Viewcontroller to the Window controller in order to set the slider values.
I have attach an simple code based on this exemple https://github.com/gbdavid2/DavidCodes_macOS/tree/master/NSToolbar%20with%20Storyboards/NSToolbar%20with%20Storyboards
In this exemple, the Toolbar shows a Previous and an Next button that , when clicked, they change a counter value (count). I would like to send back that value from the ViewCoOntroller to the WindowController in order to display it in label and eventually, the slider value in the toolbar. Thanks for your help.
// WindowController.swift
import Cocoa
class WindowController: NSWindowController {
#IBOutlet weak var myBoutton: NSToolbarItem!
var viewController: ViewController {
get {
return self.window!.contentViewController! as! ViewController
}
}
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.
//viewController.myLabel.stringValue = "boo"
}
#IBAction func previous(_ sender: Any) {
viewController.updateMyLabelText(newText: "Prev Button clicked! ")
}
#IBAction func next(_ sender: Any) {
viewController.updateMyLabelText(newText: "Next Button clicked! ")
}
}
import Cocoa
class ViewController: NSViewController {
var count : Int = 0
#IBOutlet weak var myLabel: NSTextField!
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
}
override var representedObject: Any? {
didSet {
// Update the view, if already loaded.
}
}
func updateMyLabelText(newText: String){
if newText.contains("Prev") {count -= 1}
else if newText.contains("Next") {count += 1}
myLabel.stringValue = newText + String(count)
}
}
Another way to to achieve this is with Cocoa Bindings. Example:
In the toolbar are a Previous button, a Next button and a slider. The actions of the buttons are connected to the First Responder. The action methods are implemented in ViewController. The count property of ViewController has attributes #objc dynamic so it can be used with Cocoa Bindings.
class ViewController: NSViewController {
#objc dynamic var count: Int = 0
#IBAction func previous(_ sender: Any) {
count -= 1
}
#IBAction func next(_ sender: Any) {
count += 1
}
}
The slider in the toolbar is bound to the Window Controller, key path window.contentViewController.count.
In the view is a label with a number formatter. The value of the label is bound to the View Controller, key path count.
The window controller isn't subclassed.
There are multiple ways to achieve this.
One of the way is by creating a class [e.g: SliderManager] which keep tracks of current value and handles increment/decrement. You can get the current value of Slider with the help of Singleton in any Controller.
Here is an example implementation:
protocol SliderCountDelegate: NSObject {
func counterDidUpdate()
}
final class SliderCountManager {
static let shared = SliderCountManager()
var value: UInt8 = 0 // <-- Unsigned Integers: Only Positive numbers
weak var delegate: SliderCountDelegate?
public func increaseCounter() {
value += 1
delegate?.counterDidUpdate()
}
public func decreaseCounter() {
value -= 1
delegate?.counterDidUpdate()
}
}
Here is how you should use this in your code:
// WindowController.swift
import Cocoa
class WindowController: NSWindowController {
#IBOutlet weak var myBoutton: NSToolbarItem!
override func windowDidLoad() {
super.windowDidLoad()
}
#IBAction func previous(_ sender: Any) {
SliderCountManager.shared.increaseCounter()
print(SliderCountManager.shared.value) // <- Accessing Current value here
}
#IBAction func next(_ sender: Any) {
SliderCountManager.shared.decreaseCounter()
print(SliderCountManager.shared.value)
}
}
import Cocoa
class ViewController: NSViewController, SliderCountDelegate {
#IBOutlet weak var myLabel: NSTextField!
override func viewDidLoad() {
super.viewDidLoad()
SliderCountManager.shared.delegate = self // Set Delegate to `self`
}
override var representedObject: Any? {
didSet {
}
}
// Protocol conformance
func counterDidUpdate() {
myLabel.stringValue = String(SliderCountManager.shared.value)
}
}
Thanks for the proposed solutions. It certainly put me in the wrigth direction.
Here is what I did. In the WindowController , I set a toolbar with 1) button «previous», 2) button «next» and 3) a slider «slider».
Those are linked to the proper IBOutler and IBaction in the WindowController.
The viewController have a textLabel «myLabel»
The 2 buttons and the slider change the slider_ptr value in the ViewControler and is sent to myLabel. Also, the slider.label change according to the slider_pointer and the slider_max values. Here is the code for the windowController:
import Cocoa
class WindowController: NSWindowController {
#IBOutlet weak var slider: NSSlider!
#IBOutlet weak var sliderTB: NSToolbarItem!
var viewController: ViewController {
get {
return self.window!.contentViewController! as! ViewController
}
}
override func windowDidLoad() {
super.windowDidLoad()
setSlider() // set initial value based on ViewController
}
#IBAction func previous(_ sender: Any) {
viewController.previous (WindowController())
setSlider()
}
#IBAction func next(_ sender: Any) {
//viewController.updateMyLabelText(newText: "Prev Button clicked! ")
viewController.next (WindowController()) //send to VC function previous
// let pt = viewController.slider_ptr + 1
//let sMax = viewController.slider_max
setSlider()
//sliderTB.label = String(pt) + " de " + String(sMax)
}
#IBAction func sliderDidChange(_ sender: Any) {
viewController.sliderDidSlide (WindowController(), pointer: Int(slider.doubleValue))
setSlider()
// viewController.sliderDidSlide(PosiWC(), sValue: myslider.doubleValue)
}
func setSlider() {
/* myslider.minValue = 1
myslider.maxValue = Double(max)
myslider.integerValue = pointer*/
//print ("WCP58:" , myslider.integerValue )
let pt = viewController.slider_ptr
let sMax = viewController.slider_max
//slider (max : pt, pointer: sMax)
sliderTB.label = String(pt) + " de " + String(sMax)
slider.minValue = 1
slider.maxValue = Double(sMax)
slider.integerValue = pt
}
}
and for the Viewcontroller :
class ViewController: NSViewController {
var slider_ptr = 1 // slider position
var slider_max: Int = 0 //
#IBOutlet weak var myLabel: NSTextField!
override func viewDidLoad() {
super.viewDidLoad()
slider_max = 250
myLabel.stringValue = String(slider_ptr)
}
override var representedObject: Any? {
didSet {
}
}
func previous(_ sender: Any) {
if slider_ptr > 1 {
slider_ptr -= 1
}
else { NSSound.beep()}
myLabel.stringValue = String(slider_ptr)
}
func next(_ sender: Any) {
if slider_ptr < slider_max {
slider_ptr += 1
}
else { NSSound.beep()}
myLabel.stringValue = String(slider_ptr)
}
func sliderDidSlide(_ sender: Any, pointer : Int) {
print (pointer)
slider_ptr = pointer
myLabel.stringValue = String(slider_ptr)
}
}

How to execute func present in a ViewController from another?

I am a beginner in Swift, and I do not yet understand all the elements.
I am trying to execute a function present in a ViewController (ProjectTabBarController) from another ViewController (ProjectInfosViewController). I end up with an error when I execute the function from the second.
For the context, it is for a navigation button of 3 UIViewController belonging to a UITabBarViewController, itself embedded in a UINavigationController
Thank you in advance ! (Sorry for my bad English)
import UIKit
//MARK:-TAB CONTROLLER
class ProjectTabBarController: UITabBarController {
#IBOutlet weak var ui_saveButton: UIBarButtonItem!
override func viewDidLoad() {
super.viewDidLoad()
}
#IBAction func saveAction(_ sender: Any) {
// code
disableSaveButton() // ALL IT'S FINE HERE
}
func enableSaveButton() {
ui_saveButton.title = "Save"
ui_saveButton.isEnabled = true
}
func disableSaveButton() {
ui_saveButton.title = "Saved"
ui_saveButton.isEnabled = false
} }
//MARK:-PROJECT INFORMATIONS
class ProjectInfosViewController: UIViewController, UITextFieldDelegate {
let superController = ProjectTabBarController()
override func viewDidLoad() {
super.viewDidLoad()
}
func textFieldDidChangeSelection(_ textField: UITextField) {
superController.enableSaveButton() // BUT HERE, DOESN'T
} }
//MARK:-PROJECT FIXTURES
class ProjectFixturesViewController: UIViewController, UITableViewDataSource {
}
//MARK:-PROJECT CONTACT
class ProjectContactViewController: UIViewController {
}
This
let superController = ProjectTabBarController()
is a new vc that's not presented , if the vc is inside the tabController then do
let res = self.tabBarController as! ProjectTabBarController
res.......// call what you need

delegation (while creating sideMenu, delegate? returns nil)

guys.
I'm asking for help. It seems a very easy task, but I can solve it for the whole day.
I'm trying to create a side menu using container view. When a user presses More button(barButtonItem), the whole view slide to the right and menu table appears. I know how to make it using Notifications. But I would like to solve it through delegation. Here is my storyboard.
enter image description here
and code:
import UIKit
class RootViewController: UIViewController, SideMenuDelegate {
#IBOutlet weak var leading: NSLayoutConstraint!
var sideMenuIsOpen = false
var sideMenu: MainViewController?
override func viewDidLoad() {
super.viewDidLoad()
sideMenu?.delegate = self
}
func openSideMenu() {
toggleSideMenu()
}
func toggleSideMenu() {
if sideMenuIsOpen {
leading.constant = 0
} else {
leading.constant = 240
}
}
}
and:
import UIKit
protocol SideMenuDelegate {
func openSideMenu()
}
class MainViewController: UIViewController {
var delegate: SideMenuDelegate?
#IBAction func toggleSideMenu(_ sender: UIBarButtonItem) {
if let delegateUnwrapped = delegate {
delegateUnwrapped.openSideMenu()
} else {
print("nil")
}
}
override func viewDidLoad() {
super.viewDidLoad()
BackgroundImageView.createBackground(insideView: self, image: .mainViewBackground)
}
}
Thank you!
This
var sideMenu: MainViewController? // is nil
override func viewDidLoad() {
super.viewDidLoad()
sideMenu?.delegate = self
}
has no reference to the current displayed main , it's nil when you present the main from the Root give it the reference

Swift Transferring data to the first view by pressing the "Back" button

Hello friends . Navigation control to the second screen. I need to go
to the one screen with the button(Sonucları Listele) on the second screen and I have to
make the number on the first screen to "2"
image 1
image 2
First View
class KonularViewController: UIViewController {
var number : Int?
#IBAction func barButtonKonuEkle(_ sender: Any) {
let childViewController = storyboard?.instantiateViewController(withIdentifier: "KonuEkleViewController") as! KonuEkleViewController
navigationController?.pushViewController(childViewController, animated: true)
}
}
Second View
class AramaViewController: UIViewController {
#IBOutlet weak var btn1: UIButton!
#IBOutlet weak var btn2: UIButton!
override func viewDidLoad() {
super.viewDidLoad()
btn1.isSelected = true
}
#IBAction func btnListele(_ sender: Any) {
//First View "Number" variable on the first screen will be 2
}
#IBAction func btn_box(sender: UIButton) {
if sender.titleLabel?.text == "En Yeniler"
{
btn1.isSelected = true
btn2.isSelected = false
}
else
{
btn2.isSelected = true
btn1.isSelected = false
}
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
}
One strategy would be to have a 3rd class that is your Model, which can hold state.
class Model {
static let shared = Model()
var count: Int = 1
}
class AramaViewController: UIViewController {
#IBAction fund btnListele(_ sender: Any) {
Model.shared.count += 1
//First View "Number" variable on the first screen will be 2
}
class KonularViewController: UIViewController {
override func viewWillAppear(animated:Bool) {
super.viewWillAppear(animated: animated)
numberView.text = "\(Model.shared.count)" //display your number here
}
}
Another Option
Reach back in the Navigation Controller View Controllers array to the previous view and set a property. This is a bit more fragile.
class KonularViewController: UIViewController {
var count: Int = 1
override func viewWillAppear(animated:Bool) {
super.viewWillAppear(animated: animated)
numberView.text = "\(count)" //display your number here
}
}
class AramaViewController: UIViewController {
#IBAction fund btnListele(_ sender: Any) {
let numberOfViews = navigationController.viewControllers.count
if count > 1, let previousViewController = self.navigationController.viewControllers[numberOfViews-2] as? KonularViewController
previousViewController.count += 1
//First View "Number" variable on the first screen will be 2
}
Assuming KonularViewController identifier is "KonularViewController".
In AramaViewController:
#IBAction func btnListele(_ sender: Any) {
//First View "Number" variable on the first screen will be 2
let konularViewController = storyboard?.instantiateViewController(withIdentifier: "KonularViewController") as! KonularViewController
konularViewController.number = 2
navigationController?.pushViewController(childViewController, animated: true)
}

Swift: Updating a label from a second view controller

I have two view controllers. I also have a universal variable called number. The first view controller has a label on it called mainLabel. My second view controller has a button on it. When the button is pressed it should subtract 200 from the variable number then update the mainLabel label. I can not figure out how to make mainLabel a label that works on the second view controller too.
First View Controller
import UIKit
var number:Int = 0
class ViewController: UIViewController {
#IBOutlet weak var mainLabel: UILabel!
#IBAction func backgroundButton(sender: AnyObject) {
number = number + 1
mainLabel.text = "\(number)"
NSUserDefaults.standardUserDefaults().setObject(number, forKey: "number")
}
override func viewDidLoad() {
super.viewDidLoad()
if NSUserDefaults.standardUserDefaults().objectForKey("number") != nil {
number = NSUserDefaults.standardUserDefaults().objectForKey("number") as! Int
}
mainLabel.text = "\(number)"
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
}
Second View Controller
import UIKit
class SecondViewController: UIViewController {
#IBOutlet weak var buy1Label: UILabel!
#IBAction func buy1(sender: AnyObject) {
number = number - 200
buy1Label.text = "Bought!"
mainLabel.text = "\(number)"
}
}
class ViewController: UIViewController {
#IBOutlet weak var mainLabel: UILabel!
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
NSNotificationCenter.defaultCenter().addObserverForName("NSNotificationName", object: nil, queue: nil) { (note) -> Void in
// Number changed, update your UILabel.
var number: Int = NSUserDefaults.standardUserDefaults().integerForKey("keyOfNumber")
self.mainLabel.text = "\(number)"
}
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
#IBAction func subtractNumberBy200() {
var number: Int = NSUserDefaults.standardUserDefaults().integerForKey("keyOfNumber")
number -= 200
NSUserDefaults.standardUserDefaults().setInteger(number, forKey: "keyOfNumber")
}
}
Hope this will works for you.
Wow, this question cuts to the core of what I have to deal with every day. Here is my first take on how to do this with notifications.
First, setup some common global things.
let NumberDidChangeNote = "NumberDidChangeNote" // A name for the notification.
// A function to get the value of number the same way every time.
func number() -> Int {
return NSUserDefaults.standardUserDefaults().integerForKey("number");
}
// A function to set the value of number the same way every time.
func setNumber(number: Int) {
NSUserDefaults.standardUserDefaults().setInteger(number, forKey: "number")
NSUserDefaults.standardUserDefaults().synchronize()
// Post a number did change notification
NSNotificationCenter.defaultCenter().postNotificationName(NumberDidChangeNote, object: nil)
}
The first view controller splits the roles of setting number and setting the label.
class ViewController: UIViewController {
#IBOutlet weak var mainLabel: UILabel!
#IBAction func backgroundButton(sender: AnyObject) {
setNumber(number() + 1)
}
dynamic func numberDidChange(note: NSNotification) {
mainLabel.text = "\(number())"
}
override func viewWillAppear(animated: Bool) {
super.viewWillAppear(animated)
// Add an observer which will call numberDidChange() anytime the number changes.
let center = NSNotificationCenter.defaultCenter()
center.addObserver(self, selector: "numberDidChange", name: NumberDidChangeNote, object: nil)
// Fake an initial notification to numberDidChange() to set the initial value of the label.
numberDidChange(NSNotification(name: NumberDidChangeNote, object: nil))
}
override func viewWillDisappear(animated: Bool) {
// Remove the observer when not on the screen.
let center = NSNotificationCenter.defaultCenter()
center.removeObserver(self, name: NumberDidChangeNote, object: nil)
super.viewWillDisappear(animated)
}
}
Now the second view controller doesn't have to worry about the first view controller at all.
class SecondViewController: UIViewController {
#IBOutlet weak var buy1Label: UILabel!
#IBAction func buy1(sender: AnyObject) {
setNumber(number() - 200)
buy1Label.text = "Bought!"
}
}