how I should send data from xib to viewcontroller? - swift

i have a view that is a xib, this view contains a buttons for a calculator, I did this because I need a custom keyboard for my app, my app has some views that needs this keyboard
the problem is, how I send the data from view to my view controller?
in my view controller I only has a textfield and a view with xib custom class
I use swift 4.2
custom view and textflied
this is my code from my xib
import UIKit
class keyboardView: UIView {
#IBOutlet var viewKeyboard: UIView!
var textIntroduced = ""
override init(frame: CGRect) { // for using CustomView in code
super.init(frame: frame)
custom()
}
required init?(coder aDecoder: NSCoder)
{
super.init(coder: aDecoder)
custom()
}
private func custom()
{
Bundle.main.loadNibNamed("keyboard", owner: self, options: nil)
viewKeyboard.frame = self.bounds
viewKeyboard.autoresizingMask = [.flexibleHeight,.flexibleWidth]
for view in viewKeyboard.subviews
{
view.isExclusiveTouch = true
}
addSubview(viewKeyboard)
}
#IBAction func addOne(_ sender: Any) {
textIntroduced += "1"
}
#IBAction func addTwo(_ sender: Any) {
textIntroduced += "2"
}
#IBAction func addThree(_ sender: Any) {
textIntroduced += "3"
}
#IBAction func addFour(_ sender: Any) {
textIntroduced += "4"
}
#IBAction func addFive(_ sender: Any) {
textIntroduced += "5"
}
#IBAction func addSix(_ sender: Any) {
textIntroduced += "6"
}
#IBAction func addSeven(_ sender: Any) {
textIntroduced += "7"
}
#IBAction func addEight(_ sender: Any) {
textIntroduced += "8"
}
#IBAction func addNine(_ sender: Any) {
textIntroduced += "9"
}
#IBAction func addZero(_ sender: Any) {
textIntroduced += "0"
print(textIntroduced)
}
#IBAction func removeNumber(_ sender: Any) {
textIntroduced.removeLast()
}
}
in my view controller I only has a textfield and view with custom class
i want to push any button view and the result should be written in the textfield.

You can use protocol to observe data changes in your xib. First of all you need to create a protocol like this.
protocol NumberCalculable: class {
func addNumber(_ number: Int)
}
Then, inside your xib file below your viewKeyboard outlet you need to create a delegate for your protocol.
weak var delegate: NumberCalculable?
Instead of doing textIntroduced += 1 you should change with this delegate?.addNumber(1) and same for other IBAction methods.
Thirdly, you need to conform your protocol in your viewController class doing
keyboardView.delegate = self inside viewDidLoad() method.
extension ViewController: NumberCalculable {
func addNumber(_ number: Int) {
// do whatever you want
}
}
Hope this helps.

Related

Dynamically changing background color in VC

I am stuck with this piece of my homework. Maybe someone can explain me how to solve it.
"VC contains a controller with a built-in controller. Both the parent and child controller have three buttons: Green, Yellow, Violet. When you click on one of the buttons in the parent controller, the background color of the child controller changes to the appropriate one. When you click on the button in the child, the background of the parent changes."
Here is what I made in my code
Parent VC
import UIKit
class OrangeViewController: UIViewController, VioletControllerDelegate {
var delegate: VioletControllerDelegate?
override func viewDidLoad() {
super.viewDidLoad()
}
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
let vcV = segue.destination as! VioletViewController
vcV.bgColor = view.backgroundColor
vcV.delegate = self
}
#IBAction func greenOButton(_ sender: Any) {
//TO DO
}
#IBAction func yellowOButton(_ sender: Any) {
//TO DO
}
#IBAction func purpleOButton(_ sender: Any) {
//TO DO
}
func setColor(color: String) {
view.backgroundColor = UIColor(named: color)
}
}
Child VC
import UIKit
protocol VioletControllerDelegate{
func setColor ( color : String)
}
class VioletViewController: UIViewController {
var bgColor : UIColor?
var delegate: VioletControllerDelegate?
override func viewDidLoad() {
super.viewDidLoad()
var bgColor = view.backgroundColor
}
#IBAction func setGreen(_ sender: Any) {
delegate?.setColor( color: "green")
}
#IBAction func setYellow(_ sender: Any) {
delegate?.setColor( color: "yellow")
}
#IBAction func setViolet(_ sender: Any) {
delegate?.setColor( color: "violet")
}
func setColor ( color : String){
view.backgroundColor = UIColor(named: color)
}
}
Thank you!
I did it. In case someone will need something like this I am posting my answer:
Parent VC
import UIKit
class OrangeViewController: UIViewController, VioletControllerDelegate {
var childVC: VioletViewController?
override func viewDidLoad() {
super.viewDidLoad()
}
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
let vcV = segue.destination as! VioletViewController
self.childVC = vcV
vcV.delegate = self
}
#IBAction func greenOButton(_ sender: Any) {
childVC?.view.backgroundColor = UIColor.green
}
#IBAction func yellowOButton(_ sender: Any) {
childVC?.view.backgroundColor = UIColor.yellow
}
#IBAction func purpleOButton(_ sender: Any) {
childVC?.view.backgroundColor = UIColor.purple
}
func setColor( color : UIColor) {
view.backgroundColor = color
}
}
Child VC
import UIKit
protocol VioletControllerDelegate{
func setColor ( color : UIColor)
}
class VioletViewController: UIViewController {
var delegate: VioletControllerDelegate?
override func viewDidLoad() {
super.viewDidLoad()
}
#IBAction func setGreen(_ sender: Any) {
delegate?.setColor( color: UIColor.green)
}
#IBAction func setYellow(_ sender: Any) {
delegate?.setColor( color: UIColor.yellow)
}
#IBAction func setViolet(_ sender: Any) {
delegate?.setColor( color: UIColor.purple)
}
}

i cannot able to pass data between viewcontrollers via protocols

View controller A
class ViewController: UIViewController {
var delegate: server?
override func viewDidLoad() {
super.viewDidLoad()
}
#IBAction func ok(_ sender: Any) {
delegate?.datum(data: "sd")
performSegue(withIdentifier: "goingB", sender: self)
}
}
View controller B
protocol server {
func datum(data: String)
}
class ViewControllerB: UIViewController, server {
#IBOutlet weak var label: UILabel!
override func viewDidLoad() {
super.viewDidLoad()
}
func datum(data: String) {
self.label.text = data
print(data)
}
}
I need to pass the data via view controllers but I cannot able to pass however I know we can pass data through protocols, but anyhow I end up with error when try to run the program
If you need to pass data from one view controller to another and you're using segue for presenting new view controller, you can just override prepare(for:sender:), there is no need to using delegates. Here you can get reference for controller which will be presented and you can assign its variable.
So, first create variable in second view controller and declare that if you assign it with new value, it changes text of your label
class ViewControllerB: UIViewController {
#IBOutlet weak var label: UILabel!
var variable: String? {
didSet {
label.text = variable
}
}
}
Now in first view controller override prepare(for:sender:) and if segue is segue which you've performed, downcast destination view controller and assign its variable
class ViewController: UIViewController {
#IBAction func ok(_ sender: Any) {
performSegue(withIdentifier: "goingB", sender: self)
}
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == "goingB" {
let destinationVC = segue.destination as! ViewControllerB
destinationVC.variable = "sd"
}
}
}
Anyway, if you want to use your code with delegate, you have to set delegate of first view controller as second view controller which will be presented. For this purpose you can also use prepare(for:sender:) where you can get reference for destination of segue and then you can call your method on delegate
class ViewController: UIViewController {
var delegate: server?
#IBAction func ok(_ sender: Any) {
performSegue(withIdentifier: "goingB", sender: self)
}
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == "goingB" {
let destinationVC = segue.destination as! ViewControllerB
delegate = destinationVC
delegate?.datum(data: "sd")
}
}
}
Notes:
Name protocol with big capital letter Server and we are talking about delegates, add delegate word: ServerDelegate
Constrain protocol for just for classes
Make then your delegate variable weak
protocol ServerDelegate: class {
func datum(data: String)
}
...
weak var delegate: ServerDelegate?
The simplest here is to to set the property directly in prepare.
However, if you want to use delegate, you can. Your problem is that you have mixed between A and B.
The way you wrote it, when you call delegate?.datum, delegate is not defined and we can't access datum.
What do you want to do ? Go from A to B, and when in B, update a label in B with data received from A.
Here just to show how to use (but clearly too complex compared with direct assignment).
protocol Server {
func datum() -> String
}
class ViewControllerB: UIViewController {
#IBOutlet weak var label: UILabel!
var delegate: Server?
override func viewDidLoad() {
super.viewDidLoad()
let data = delegate?.datum()
self.label.text = data
}
}
class ViewControllerA: UIViewController, Server {
override func viewDidLoad() {
super.viewDidLoad()
}
var data = "sd"
func datum() -> String {
return data
}
#IBAction func ok(_ sender: Any) {
performSegue(withIdentifier: "goingB", sender: self)
}
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if let destVC = segue.destination as? ViewControllerB {
destVC.delegate = self
}
}
}

Swiching between 2 diferent NSViewControllers with data

I'm absolute newbie in Swift and OSX development, and I'm sorry if my question will be too noob. I want to understand principles of navigation between NSViewControllers.
I have my default ViewController, where are login and password fields and button to login. After click on button, returns token. And now I trying to change "view" to SecondViewController and save somewhere token, I will need it in future. How can I do it? and it possible to do this in function?:
#IBAction func loginButton(_ sender: Any) {
....
}
Thank you!
You need to use segues to perform this action.
First make the segues connections between the ViewControllers using to storyboard editor. After that you need to give the segues an identifier on the storyboard's attributes inspector. Then in your code you can call the new ViewController by the segue like the code below.
With this code you can pass the data using the button:
class ViewController: NSViewController {
var dataToPass: String = "DataToPass"
override func viewDidLoad() {
super.viewDidLoad()
}
#IBAction func loginButton(_ sender: Any) {
performSegue(withIdentifier: NSStoryboardSegue.Identifier(rawValue: "segueIdentifier"), sender: self)
}
override func prepare(for segue: NSStoryboardSegue, sender: Any?) {
if segue.identifier!.rawValue == "segueIdentifier" {
let destinationViewController = segue.destinationController as! ViewController2
destinationViewController.dataToReceive = dataToPass
}
}
}
class ViewController2: NSViewController {
var dataToReceive: String
override func viewDidLoad() {
super.viewDidLoad()
}
}
And with this code you will use the override viewWillAppear
class ViewController: NSViewController {
var dataToPass: String = "DataToPass"
override func viewDidLoad() {
super.viewDidLoad()
}
override func viewWillAppear() {
performSegue(withIdentifier: NSStoryboardSegue.Identifier(rawValue: "segueIdentifier"), sender: self)
}
override func prepare(for segue: NSStoryboardSegue, sender: Any?) {
if segue.identifier!.rawValue == "segueIdentifier" {
let destinationViewController = segue.destinationController as! ViewController2
destinationViewController.dataToReceive = dataToPass
}
}
}
class ViewController2: NSViewController {
var dataToReceive: String
override func viewDidLoad() {
super.viewDidLoad()
}
}
In both cases you need to assure the data you want to pass to the other view controller is not null.

Swift App runs but no buttons appear

I wrote a Swift app but only the window appears when it runs. I can't see any buttons.
Here is my code... I've tried removing the .white attribute thinking maybe it was hidden behind a layer. Nothing.
//
// ViewController.swift
// BraviaRemote
//
// Created by Ed Gilroy on 7/2/17.
// Copyright © 2017 Edward Williams. All rights reserved.
//
import Cocoa
import Alamofire
class ViewController: NSViewController, NSTextFieldDelegate {
#IBAction func MenuButton(_ sender: NSButtonCell) {
triggerRemoteControl(irccc: "AAAAAQAAAAEAAABgAw==")
}
#IBAction func ReturnButton(_ sender: NSButton) {
triggerRemoteControl(irccc: "AAAAAgAAAJcAAAAjAw==")
}
#IBAction func InfoButton(_ sender: NSButton) {
triggerRemoteControl(irccc: "AAAAAQAAAAEAAAA6Aw==")
}
#IBAction func GuideButton(_ sender: NSButton) {
triggerRemoteControl(irccc: "AAAAAgAAAKQAAABbAw==")
}
#IBAction func SelectButton(_ sender: NSButton) {
triggerRemoteControl(irccc: "AAAAAQAAAAEAAABlAw==")
}
#IBAction func ChnUpButton(_ sender: NSButton) {
triggerRemoteControl(irccc: "AAAAAQAAAAEAAAAQAw==")
}
#IBAction func ChnDownButton(_ sender: NSButton) {
triggerRemoteControl(irccc: "AAAAAQAAAAEAAAARAw==")
}
#IBAction func VolUpButton(_ sender: NSButton) {
triggerRemoteControl(irccc: "AAAAAQAAAAEAAAASAw==")
}
#IBAction func VolDownButton(_ sender: NSButton) {
triggerRemoteControl(irccc: "AAAAAQAAAAEAAAATAw==")
}
#IBAction func LeftButton(_ sender: NSButton) {
triggerRemoteControl(irccc: "AAAAAQAAAAEAAAA0Aw==")
}
#IBAction func RightButton(_ sender: NSButton) {
triggerRemoteControl(irccc: "AAAAAQAAAAEAAAAzAw==")
}
#IBAction func UpButton(_ sender: NSButton) {
triggerRemoteControl(irccc: "AAAAAQAAAAEAAAB0Aw==")
}
#IBAction func DownButton(_ sender: NSButton) {
triggerRemoteControl(irccc: "AAAAAQAAAAEAAAB1Aw==")
}
#IBAction func OnOffButton(_ sender: NSSegmentedControl){
}
#IBOutlet weak var IPField: NSTextField!
var IPAddress: String? {
didSet {
if IPField != nil { IPAddress = "http://\(IPAddress!)/sony/IRCC?" }
else {IPAddress = "http://192.168.2.7/sony/IRCC?"}
if let ip = IPAddress { print (ip) } //Unwraps optional
}
}
override func controlTextDidChange(_ obj: Notification) {
if let txtField = obj.object as? NSTextField {
if txtField.tag == 0 {
//Validation (for later)
IPAddress = txtField.stringValue
}
}
}
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
func viewDidLoad() {
super.viewDidLoad()
}
}
override func viewDidAppear() {
// Window Properties, including solid colour, lack of resize, movable by background.
view.window?.titlebarAppearsTransparent = true
view.window?.backgroundColor = NSColor.white
view.window?.styleMask.remove(.resizable)
view.window?.isMovableByWindowBackground = true
}
override var representedObject: Any? {
didSet {
// Update the view, if already loaded.
}
}
struct SOAPEncoding: ParameterEncoding {
let service: String
let action: String
let IRCCC: String
func encode(_ urlRequest: URLRequestConvertible, with parameters: Parameters?) throws -> URLRequest {
var urlRequest = try urlRequest.asURLRequest()
guard parameters != nil else { return urlRequest }
if urlRequest.value(forHTTPHeaderField: "Content-Type") == nil {
urlRequest.setValue("text/xml", forHTTPHeaderField: "Content-Type")
}
let soapBody = "<?xml version=\"1.0\" encoding=\"utf-8\"?><s:Envelope xmlns:s=\"http://schemas.xmlsoap.org/soap/envelope/\" s:encodingStyle=\"http://schemas.xmlsoap.org/soap/encoding/\"><s:Body><u:\(action) xmlns:u=\"\(service)\"><IRCCCode>\(IRCCC)</IRCCCode></u:X_SendIRCC></s:Body></s:Envelope>"
urlRequest.httpBody = soapBody.data(using: String.Encoding.utf8)
return urlRequest
}
}
func triggerRemoteControl(irccc: String) {
Alamofire.request(IPAddress!,
method: .post,
parameters: ["parameter" : "value"],
encoding: SOAPEncoding(service: "urn:schemas-sony-com:service:IRCC:1",
action: "X_SendIRCC", IRCCC: irccc)).responseString { response in
print(response)
}
}
}
Three errors:
First, you are overriding viewDidLoad() and defining another viewDidLoad() inside of it.
Your code:
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
func viewDidLoad() {
super.viewDidLoad()
}
}
Should just look like this:
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
}
Second, you are overriding viewDidAppear but never calling super.
Your code:
override func viewDidAppear() {
// Window Properties, including solid colour, lack of resize, movable by background.
view.window?.titlebarAppearsTransparent = true
view.window?.backgroundColor = NSColor.white
view.window?.styleMask.remove(.resizable)
view.window?.isMovableByWindowBackground = true
}
Should look like this:
override func viewDidAppear() {
super.viewDidAppear()
// Window Properties, including solid colour, lack of resize, movable by background.
view.window?.titlebarAppearsTransparent = true
view.window?.backgroundColor = NSColor.white
view.window?.styleMask.remove(.resizable)
view.window?.isMovableByWindowBackground = true
}
Third, you are overriding the IPAdress didSet and then setting it again. This will cause an infinite loop. You are also comparing a textField to nil, which it will never be, because it's a NSTextField!, instead of checking whether it's empty or not. I can't really make sense of what you're trying to achieve here but you should rip all this overriding nonsense out until you can clearly formulate your intention.

Using a Singleton to pass data in Watchkit

I've used a Singleton in IOS with success before, but the same approach isn't working for me in watchkit...any idea why my second interface controller displays 0 (initialized value) instead of the numbers entered in the first interface controller?
class Singleton {
static let instance = Singleton()
var salesPriceAsInt: Int = 0
}
import WatchKit
import Foundation
class InterfaceController: WKInterfaceController {
override func awakeWithContext(context: AnyObject?) {
super.awakeWithContext(context)
// Configure interface objects here.
}
var salesPrice = ""
#IBOutlet weak var salesPriceLabel: WKInterfaceLabel!
func addCharacter(char: String) {
salesPrice += char
}
#IBAction func zeroButton() {
addCharacter("0")
salesPriceLabel.setText(salesPrice)
}
#IBAction func oneButton() {
addCharacter("1")
salesPriceLabel.setText(salesPrice)
}
#IBAction func twoButton() {
addCharacter("2")
salesPriceLabel.setText(salesPrice)
}
#IBAction func threeButton() {
addCharacter("3")
salesPriceLabel.setText(salesPrice)
}
#IBAction func fourButton() {
addCharacter("4")
salesPriceLabel.setText(salesPrice)
}
#IBAction func fiveButton() {
addCharacter("5")
salesPriceLabel.setText(salesPrice)
}
#IBAction func sixButton() {
addCharacter("6")
salesPriceLabel.setText(salesPrice)
}
#IBAction func sevenButton() {
addCharacter("7")
salesPriceLabel.setText(salesPrice)
}
#IBAction func eightButton() {
addCharacter("8")
salesPriceLabel.setText(salesPrice)
}
#IBAction func nineButton() {
addCharacter("9")
salesPriceLabel.setText(salesPrice)
}
#IBAction func segueButton() {
Singleton.instance.salesPriceAsInt = salesPrice.toInt()!
salesPriceLabel.setText("\(Singleton.instance.salesPriceAsInt)")
}
import WatchKit
import Foundation
class SecondPageInterfaceController: WKInterfaceController {
#IBOutlet weak var totalSaleCommissionLabel: WKInterfaceLabel!
override func awakeWithContext(context: AnyObject?) {
super.awakeWithContext(context)
}
#IBAction func secondPageButton() {
totalSaleCommissionLabel.setText("\(Singleton.instance.salesPriceAsInt)")
}
override func willActivate() {
// This method is called when watch view controller is about to be visible to user
super.willActivate()
}
override func didDeactivate() {
// This method is called when watch view controller is no longer visible
super.didDeactivate()
}
Turns out the Singleton works, what doesn't is enabling a button to both (1) store to the Singleton and (2) segue to my 2nd interface controller. To get around this I moved
Singleton.instance.salesPriceAsInt = salesPrice.toInt()!
to the didActivate method