Updating Inactive Window - swift

How do you update an inactive window?
I have an application with 2 windows. One is for user input and is the main window by default. The second is just to display values in NSTextFields and is generally inactive. I'm having trouble updating elements in the second window.
Here's minimal code which reproduces the problem (Swift 3):
import Cocoa
class ViewController: NSViewController {
#IBOutlet var logArea: NSScrollView!
#IBOutlet var logText: NSTextView!
var windowController: NSWindowController
var vc: ViewController2
#IBAction func runButton(_ sender: Any) {
displayText(text: "Running")
vc.updateInput(value: 1.0005)
}
required init?(coder decoder: NSCoder) {
let storyboard = NSStoryboard(name: "Main",bundle: nil)
windowController = storyboard.instantiateController(withIdentifier: "WindowID") as! NSWindowController
windowController.window?.makeKeyAndOrderFront(nil)
vc = storyboard.instantiateController(withIdentifier: "ViewID") as! ViewController2
vc.loadView()
super.init(coder: decoder)
}
func displayText(text: String) {
logText.textStorage?.append(NSAttributedString(string: text + "\n"))
}
}
class ViewController2: NSViewController {
#IBOutlet var input0: NSTextField!
#IBAction func updateButton(_ sender: Any) {
updateInput(value: 1.0)
}
func updateInput(value: Double) {
if input0.doubleValue == 1.0 { input0.doubleValue = 0.0 }
else { input0.doubleValue = value }
}
}
vc.updateInput(value: 1.0005) in ViewController doesn't work, but updateButton in ViewController2 does.
Any help would be appreciated! Thanks!

Related

Swift transit from vc to another vc

ViewController has a label and a button for go to secondVC. And secondVC has a text field , label , button to write user-entered text in the text field on the label. When user press the back button of navigation bar, I want transit secondVC's label's text to ViewController's label's text. How can I do this ?
ViewController's code:
import UIKit
class ViewController: UIViewController {
#IBOutlet weak var nameLabel: UILabel!
override func viewDidLoad() {
super.viewDidLoad()
}
#IBAction func goVC2(_ sender: Any) {
performSegue(withIdentifier: "toVC2", sender: nil)
}
}
secondVC's code:
import UIKit
class secondVC: UIViewController {
#IBOutlet weak var nameField: UITextField!
#IBOutlet weak var resultLabel: UILabel!
override func viewDidLoad() {
super.viewDidLoad()
}
#IBAction func saveClicked(_ sender: Any) {
resultLabel.text = nameField.text
}
}
I tried prepare for segue in ViewController and but it was error. And I searched on google for this but I couldn't find solution.
Use protocol for pass data from second VC to first VC. you need to create your own delegate method and call on dismiss with pass data, check below code :----
ViewController's code:
import UIKit
class ViewController: UIViewController, Delegate {
#IBOutlet weak var nameLabel: UILabel!
override func viewDidLoad() {
super.viewDidLoad()
}
func save(str : String) {
self.nameLabel.text = str
}
#IBAction func goVC2(_ sender: Any) {
if let vc = UIStoryboard(name: "Main", bundle: nil).instantiateViewController(withIdentifier: "secondVC") as? secondVC {
vc.delegate = self
self.present(vc, animated: true, completion: nil)
}
}
}
secondVC's code:
import UIKit
protocol Delegate : AnyObject {
func save(str : String)
}
class secondVC: UIViewController {
#IBOutlet weak var nameField: UITextField!
#IBOutlet weak var resultLabel: UILabel!
weak var delegate : Delegate?
override func viewDidLoad() {
super.viewDidLoad()
}
#IBAction func saveClicked(_ sender: Any) {
if let del = self.delegate {
let txt = nameField.text
del.save(str: txt)
self.dismiss(animated: true, completion: nil)
}
}
}

How to navigate push view controller from UIView in Swift

How to navigate PushViewController from UIView class to New View Controller, Till now what I tried with delegate/ protocol but still no success from button click, below is the swift code what I tried to navigate from uiview class
protocol MyViewDelegate {
func didTapButton()
}
class Ticket : UIView {
static let instance = Ticket()
#IBOutlet var parentView: UIView!
#IBOutlet weak var ticketView: UIView!
var delegate : MyViewDelegate?
override init (frame: CGRect) {
super.init(frame: frame)
Bundle.main.loadNibNamed("Ticket", owner: self, options: nil)
}
#IBAction func btnHistoryTicket(_ sender: ThemeButtonTicket) {
}
#IBAction func btnNewTicket(_ sender: ThemeButtonTicket) {
func buttonTapAction() {
delegate?.didTapButton() // Expect to navigate
}
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
func showTicket(){
UIApplication.shared.windows.first{$0.isKeyWindow}?.addSubview(parentView)
}
}
class ViewController: UIViewController, MyViewDelegate {
override func viewDidLoad() {
super.viewDidLoad()
let ticket = Ticket()
ticket.delegate = self
}
func didTapButton() {
let vc = kMainStoryboard.instantiateViewController(withIdentifier: "SubmitTicketVC") as! SubmitTicketVC
self.navigationController?.pushViewController(vc, animated: true)
}
}

Custom keyboard is crashing the app - Swift

I'm doing a test of a custom keyboard. This is what I need:
It has to have two UITextFields. Cannot be labels.
The keyboard is an embedded UIView.
The default keyboard should be disabled.
It cannot be a keyboard extension.
Not sure why the app is crashing. PS: Not all the keys are on the code yet. Here is an image of what I'm trying to do and the two View Controllers.
Edit: The error is: Thread 1: Fatal error: Unexpectedly found nil while unwrapping an Optional value
First ViewController:
import UIKit
class HomeVC: UIViewController, ButtonTapDelegate {
#IBOutlet var textField1: UITextField!
#IBOutlet var textField2: UITextField!
#IBOutlet var keyboardView: UIView!
var buttonPressed = [String]()
override func viewDidLoad() {
addKeyboard(view: keyboardView)
buttonPressed = [String]()
textField1.inputView = UIView()
textField2.inputView = UIView()
}
func addKeyboard(view: UIView) {
let keyboard = KeyboardVC(nibName: "KeyboardVC", bundle: nil)
view.addSubview(keyboard.view)
addChild(keyboard)
}
func didTapButton(sender: UIButton) {
if sender.tag == 5 {
textField1.text?.append(contentsOf: " ")
} else if sender.tag == 6 {
textField1.text?.removeAll()
buttonPressed = [String]()
} else {
let val = sender.titleLabel?.text
textField1.text?.append(contentsOf: val!)
}
self.textField1.text = buttonPressed.joined(separator: "")
}
}
Here is the second View Controller:
import UIKit
protocol ButtonTapDelegate {
func didTapButton(sender: UIButton)
}
class KeyboardVC: UIViewController {
var delegate: ButtonTapDelegate!
override func viewDidLoad() {
super.viewDidLoad()
}
#IBAction func buttons(_ sender: UIButton) {
delegate.didTapButton(sender: sender)
print(sender)
}
}
var delegate: ButtonTapDelegate!
An implicitly unwrapped optional is essentially a promise that you're definitely going to give the variable a value before you try to access it. The problem in this case is that you haven't done that. Most likely, you want to do this in your first view controller:
func addKeyboard(view: UIView) {
let keyboard = KeyboardVC(nibName: "KeyboardVC", bundle: nil)
keyboard.delegate = self // Now "delegate" will have a value before the function gets called
view.addSubview(keyboard.view)
addChild(keyboard)
}

Hide Custom View UIButton From UIViewController Class

Actually i have a Custom view with two button, and i want to hide it at runtime through UIViewController , So i don't get any exact thing to hide that button from UIViewcontroller class
Here is my CustomView class,
import UIKit
class BottomButtonUIView: UIView {
#IBOutlet weak var btnNewOrder: UIButton!
#IBOutlet weak var btnChat: UIButton!
override func awakeFromNib() {
super.awakeFromNib()
}
// MARK: init
required init(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)!
if self.subviews.count == 0 {
setup()
}
}
override init(frame: CGRect) {
super.init(frame: frame)
setup()
}
func setup() {
if let view = Bundle.main.loadNibNamed("BottomButtonUIView", owner: self, options: nil)?.first as? BottomButtonUIView {
view.frame = bounds
view.autoresizingMask = [.flexibleWidth, .flexibleHeight]
addSubview(view)
}
}
#IBAction func btnOrderNowClick(_ sender: Any) {
let VC1 = StoryBoardModel.orderDeatalStoryBord.instantiateViewController(withIdentifier: "NewOrderViewController") as! NewOrderViewController
VC1.isPush = false
let navController = UINavigationController(rootViewController: VC1) // Creating a navigation controller with VC1 at the root of the navigation stack.
let currentController = getCurrentVC.getCurrentViewController()
currentController?.present(navController, animated:true, completion: nil)
}
#IBAction func btnChatNowClick(_ sender: Any) {
}
func getCurrentViewController() -> UIViewController? {
if let rootController = UIApplication.shared.keyWindow?.rootViewController {
var currentController: UIViewController! = rootController
while( currentController.presentedViewController != nil ) {
currentController = currentController.presentedViewController
}
return currentController
}
return nil
}
}
I set it to UIView in StoryBoard, and then I create outlet of that view,
#IBOutlet weak var viewBottmNewOrder: BottomButtonUIView!
Now i want to hide btnNewOrder from UIViewcontroller class but when i use
viewBottmNewOrder.btnNewOrder.isHidden = true it cause null exception, Please do need full answer.
Please don't do like that. The required init(coder aDecoder: NSCoder) will call a lot of times when the BottomButtonUIView created from xib. And your custom view will look like:
[BottomButtonUIView [ BottomButtonUIView [btnNewOrder, btnChat]]].
So when you access to btnNewOrder like that:
viewBottmNewOrder.btnNewOrder it will null.
I think you should add your custom view in viewDidLoad of your `UIViewController'.

Pass data between ViewController and ContainerViewController

I'm working on an app, and need to pass data between view and containerView. I need to send data and receive data from both Views.
Let me explain better:
I can change the Label Master (Touch the Container Button) by protocol, but I can not change the Label Container (Touch the Master button). What happens is the Master connects with the container by a following. But do not have a follow Container linking to the Master.
I tried to add but segue to, but it worked.
The Master View Controller:
import UIKit
protocol MasterToContainer {
func changeLabel(text:String)
}
class Master: UIViewController, ContainerToMaster {
#IBOutlet var containerView: UIView!
var masterToContainer:MasterToContainer?
#IBOutlet var labelMaster: UILabel!
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if segue.identifier == "containerViewSegue" {
let view = segue.destinationViewController as? Container
view!.containerToMaster = self
}
}
override func viewDidLoad() {
super.viewDidLoad()
}
#IBAction func button_Container(sender: AnyObject) {
masterToContainer?.changeLabel("Nice! It's work!")
}
func changeLabel(text: String) {
labelMaster.text = text
}
}
The Container View Controller:
import UIKit
protocol ContainerToMaster {
func changeLabel(text:String)
}
class Container: UIViewController, MasterToContainer {
var containerToMaster:ContainerToMaster?
#IBOutlet var labelContainer: UILabel!
override func viewDidLoad() {
super.viewDidLoad()
}
#IBAction func button_Master(sender: AnyObject) {
containerToMaster?.changeLabel("Amazing! It's work!")
}
func changeLabel(text: String) {
labelContainer.text = text
}
}
Can someone help me?
All you need to do is keep a reference to Container in your master view controller.
That is, you should add an instance variable to Master that will hold a reference to the view controller, not just the view. You'll need to set it in prepareForSegue.
So the beginning of Master View Controller would look something like this:
class Master: UIViewController, ContainerToMaster {
#IBOutlet var containerView: UIView!
var containerViewController: Container?
#IBOutlet var labelMaster: UILabel!
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if segue.identifier == "containerViewSegue" {
containerViewController = segue.destinationViewController as? Container
containerViewController!.containerToMaster = self
}
}
And then in your button function, simply change the label using the variable you just added.
Example:
#IBAction func button_Container(sender: AnyObject) {
containerViewController?.changeLabel("Nice! It's work!")
}
This means you can get rid of your MasterToContainer protocol too.
I tested this code, so I know it works, but unfortunately I am an Objective-C dev, and know nothing about best practices in Swift. So I don't know if this is the best way to go about it, but it certainly works.
Edit:
Here's the exact code I've tested:
Master.swift:
import UIKit
class Master: UIViewController, ContainerToMaster {
#IBOutlet var containerView: UIView!
#IBOutlet var labelMaster: UILabel!
var containerViewController: Container?
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if segue.identifier == "containerViewSegue" {
containerViewController = segue.destinationViewController as? Container
containerViewController!.containerToMaster = self
}
}
#IBAction func button_Container(sender: AnyObject) {
containerViewController?.changeLabel("Nice! It's work!")
}
func changeLabel(text: String) {
labelMaster.text = text
}
}
Container.swift:
import UIKit
protocol ContainerToMaster {
func changeLabel(text:String)
}
class Container: UIViewController {
#IBOutlet var labelContainer: UILabel!
var containerToMaster:ContainerToMaster?
#IBAction func button_Master(sender: AnyObject) {
containerToMaster?.changeLabel("Amazing! It's work!")
}
func changeLabel(text: String) {
labelContainer.text = text
}
}
I solved it with this code
To send data from ViewController -> ContainerViewController
Class ViewController : UIViewController {
func sendData(MyStringToSend : String) {
let CVC = childViewControllers.last as! ContainerViewController
CVC.ChangeLabel( MyStringToSend)
}
}
in your ContainerViewController
Class ContainerViewController : UIViewController {
#IBOutlet weak var myLabel: UILabel!
func ChangeLabel(labelToChange : String){
myLabel.text = labelToChange
}
}
To send data from ContainerViewController -> ViewController
Class ContainerViewController : UIViewController {
func sendDataToVc(myString : String) {
let Vc = parentViewController as! ViewController
Vc.dataFromContainer(myString)
}
}
and in ViewController
Class ViewController : UIViewController {
func dataFromContainer(containerData : String){
print(containerData)
}
}
I hope this will help someone.
you can use this extension to access the container child
extension UIViewController {
func getContainerChild<vc:UIViewController>(_ viewController : vc,_ hasNavigation : Bool = true) -> (vc) {
guard let vc = self.children[0] as? UINavigationController else {return viewController}
if hasNavigation {
guard let childVC = vc.children[0] as? PurchasedHistoryListVC else {
return viewController}
return childVC as! vc
} else {
return vc as! vc
}
}
}
so you can do some thing like this in your view Controller
let vc = self.getContainerChild(yourChildViewControllerClass())
vc.functionName()