Change a button's characteristic outside class programatically - swift

In the code below, I want to be able to change the visibility of a button in another class, but when I try to change button.isHidden to false, the button still doesn't show up.
View Controller 1:
override viewDidLoad(){
button.isHidden = true
}
View Controller 2:
ViewController1().button.isHidden = false
How can I change the button's visibility from another controller

Calling ViewController1() creates a ViewController1 instance instead of working with the ViewController1 instance that has already been instantiated.
To access properties (in this case the button) of ViewController1 from ViewController2, you have to pass a reference to that button from ViewController1 to ViewController2 and change the properties through that reference.
You need to set the reference in your prepare(for segue) function in ViewController1.
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if segue.identifier == "mySegue {
let nextVC = segue.destination as! ViewController2
nextVC.button = sender as! UIButton
}
}
You also need to set the segue to manual and call it in ViewController1 by self.performSegue(withIdentifier: "mySegue", sender: self.button)
You need to create the property in ViewController2 and access it like this:
class ViewController2 {
var button:UIButton?
func showButtonOnVC1(){
guard let button = self.button else { return }
button.isHidden = false
}
}

Related

How to update a label on the next screen?

Say I have two screens. Screen A has a picker and a button, which triggers a segue to screen B, which displays some content depending on the option selected by the picker.
How do I have the information as to what picker was selected in A, passed to B? So far, I have A doing:
#IBAction func pickThing(_ value: Int) {
self.thing = value;
}
Which seems to work; I believe that it is detecting the value and storing it. However, when I try adding #IBOutlet weak var thingLabel: WKInterfaceLabel! to match the label in B, I can only set the value of it when the app first loads.
If I put self.thingLabel.setText("test") in the awake() function, it sets the label to "test", so that works. But changing it to self.thingLabel.setText("thing \(self.thing)") doesn't work - it sets it to whatever self.thing is initialized as, but doesn't change it later. So awake() is not the right method to use. I've also tried putting it in willActivate and in pickThing, but neither of them did anything.
Is there some method that gets called when a screen is switched to? If not, how can I send data from one screen to the next?
For example on ViewController A use this function
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if let vc = segue.destination as? ViewControllerB {
vc.thing = self.thing
}
}
Or you can use closures in same methods and callback change from B ViewController on A
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if let vc = segue.destination as? ViewControllerB {
vc.clouser = { [weak self] thingB in
guard let `self` = self else { return }
self.thing = thingB
}
}
}
You need to make a variable in view controller B titled something like "parentVC," which would be of view controller A's class. In view controller A's class, you need to call prepare(for segue UIStoryboardSegue, sender: Any?). In this method, you can access the segue's destination property, which would be view controller B. From here you can set view controller B's "parentVC" property to "self," i.e. view controller A. Then in view controller B's class you can access properties of view controller A by using the "parentVC" variable. The code in view controller A's class would look something like this:
func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.destination is ViewControllerB {
let viewControllerB = segue.destination as? ViewControllerB
viewControllerB.parentVC! = self
}
}

How to programmatically seque to multiple view controllers from a button

I have a view controller with a lot (36) of buttons, and I want each of these buttons to segue to a particular view controller based on a variable that was set earlier in the program. In other words, any button could potentially go to 15 different view controllers based on a variable that was sent to the viewcontroller containing the buttons...
I think I can make this work if I click and drag each button to every viewcontroller... but it seems silly and messy.
I tried doing something like this:
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if variable == "Whatever" {
let send = segue.destination as! AViewController
send.variablesent = (sender as! UIButton).title(for: .normal)!}
}
But this only works if I click and drag the button in the storyboard to the "AViewController".
Any help is appreciated, thanks!!
For that you can make segue from SourceViewController to DestinationViewController instead of from Button to Controller, After that when you call perfromSegue in your button action then pass button reference as sender in perfromSegue call.
#IBAction func buttonAction(_ sender: UIButton) {
self.performSegue(withIdentifier: "segueIdentifier", sender: sender)
}
Now in prepareForSegue cast sender to UIButton and set title according to it.
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if variable == "Whatever" {
let send = segue.destination as! AViewController
if let button = sender as? UIButton {
send.variablesent = button.titleLabel?.text ?? "Default value"
}
}
}

Disable textfield in destination view controller

I have two view controllers: ViewController1 and ViewController2.
My objective is, when the segue is triggered if a certain condition in ViewController1 is met a textfield in viewController2 to be disabled.
I have setup shouldPerformSegueWithIdentifier and prepareForSegue and everything works fine, but when i put the condition it crash saying that it found an error unwrapping an optional- the textfield.
my ViewController1 is :
override func shouldPerformSegueWithIdentifier(identifier: String, sender: AnyObject!) -> Bool {
if condition1=true{
return true
}
else{
return false
}
}
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject!) {
if (segue.identifier=="segue"){
let destVC:ViewController=segue.destinationViewController as! ViewController2
if n==1{
destVC.myTextField.enabled=false
}
}
}
In prepareForSegue method myTextField of ViewController2 is not initialized yet, so thats why you are getting an error unwrapping an optional textField, To solve your crash create one Bool instance inside your ViewController2 and pass its value in prepareForSegue method.
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject!) {
if (segue.identifier=="segue"){
let destVC:ViewController=segue.destinationViewController as! ViewController2
if n==1{
destVC.isEnabled=false
}
}
}
Create instance isEnabled inside ViewController2 like this and used it in the viewDidLoad of ViewController2
var isEnabled: Bool = true
override func viewDidLoad() {
super.viewDidLoad()
self.myTextField.enabled = self.isEnabled
}
The views associated with the destination controller are not yet loaded/instantiated at that point.
Create an instance boolean flag on the destination VC and set that in the prepare segue function. Then in viewDidLoad or later in the destination VC check for that switch and disable the text field.
You can set condition at your destination view controller then you can do this
myTextField.userInteractionEnabled = false
Enable and disable userInteractionEnabled of your textfield.

How to know which segue was used using Swift?

I have a main viewController and a detailsViewController. The detailsViewController has 2 buttons. Both buttons are segues back to the main controller but I want to customize the main viewController based on which segue was used. What is the best way to check which segue was used to reach a viewController so that the main viewController can be customized depending on that? - if segue1 leads to the the main viewController then I want label1 hidden. if segue2 leads to the main viewController, then I want label2 hidden.
In Main View Controller create a variable , something like
var vcOne : Bool = true
Now in DetailsViewController
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject!) {
if segue.identifier == "segue_one"
{
let mainVC : MainViewController = segue.destinationViewController as! MainViewController
secondVC.vcOne = true
}
else if segue.identifier == "segue_two"
{
let mainVC : MainViewController = segue.destinationViewController as! MainViewController
secondVC.vcOne = false
}
}
Now in MainView Controller
override func viewWillAppear(animated: Bool) {
super.viewWillAppear(animated)
//Now check here for which segue
if(vcOne)
{
// implement for button one click
}
else
{
// implement for button two click
}
}
Hope it helps you
I'd do something like to check which segue was used. You have to set an identifier to the segue in the storyboard though!
func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if segue.identifier == "yourIdentifier" {
let yourVC = segue.destinationViewController as? yourViewController
//do magic with your destination
}
}
There is a option for setting Identifier for segue. This should be unique identifier. So that you can identify which segue is activated.
Ex:
func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if segue.identifier == "Identifier1" {
let firstVC = segue.destinationViewController as? FirstViewController
} else if segue.identifier == "Identifier2" {
let secondVC = segue.destinationViewController as? SecondViewController
}
}

Resign First Responder On Push To Detail

I was wondering how to resignFirstResponder whenever I switch to my detailView in the tableView, is this something I can implement in my prepareForSegue or somewhere else.
Here is my prepareForSegue code.
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if (segue.identifier == "DetailView") {
let VC = segue.destinationViewController as! DetailViewLemon
if let indexPath = self.tableView.indexPathForSelectedRow {
let Make = self.resultSearchController.active ?
filteredTableData[indexPath.row] as String :
tableData[indexPath.row] as String
VC.sentData1 = Make
}
}
}
Any UIView (and UIWindow as well, as it is UIView subclass) has method
func endEditing(force: Bool)
This will resign any current first responder descendant in the hierarchy of the view on which you call this method.
So you can call it on the view of the previous detail view controller or at the whole application's window from the prepareForSegue or any other logic point of your program.