Swift Hide Button In Another View Controller - ios

Currently working on my first IOS application. I have a purchase button, on success this currently sets a test button on the same view controller to hidden. Code is as follows
Decleration
#IBOutlet weak var Test: UIButton!
hide button on successful purchase
Test.isHidden = true
Now this works on my Test button, which is sat in the PurchaseViewController,class is the MasterViewController.Swift. (Purchase button that initiates this method is also in the same view controller)
PlanViewController also has a button, and class is also linked to MasterViewController.Swift. This has a separate button that i wish to hide on success of the purchase button.
When I utilise the same code as above for the button, it crashes, is their a limitation on manipulating other view controllers while you are not in it? I would have thought this worked given that they both have the Masterviewcontroller.swift as the class
Thanks

Although sometimes possible, it's generally not a good idea to directly manipulate one view controller's view from another view controller, as you are trying to do. Here is how I would do what you are trying to do.
First, set a segue identifier between your two view controllers by clicking on the segue in the storyboard and going to the attributes inspector. I suggest goToMasterViewController
In both MasterViewController.swift and PurchaseViewController.swift declare a variable var buttonHidden = false
In PurchaseViewController.swift add the following code, which will be called just before your segue to MasterViewController is performed:
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if(segue.identifier == "goToMasterViewController") {
let destinationController = segue.destination as! MasterViewController
destinationController.buttonHidden = buttonHidden
}
}
When you hide the button in PurchaseViewController, also set buttonHidden = true
And finally in MasterViewController.swift:
override func viewWillAppear(_ animated: Bool) {
testButton.isHidden = buttonHidden
}

Related

How to identify the segue identifier on destination view controller?

I have two view controllers, the first one has two buttons, signup and login, the second VC does the function of signup and login stuff (I wrote functions to switch between signup and login mode), is it possible to identify if user pressed login/signup button in the first VC so the right function will be called in the second VC when performing segue?
You have tell the second view controller what to do upon the first view controller selected option (signin or signup). I would assume that you could do this by simply declaring a flag and send it to the second view controller, for instance:
Declare a boolean variable in your second view controller (let's say shouldBehavesAsLogin) which means if selection is login it should be true:
// Controller that could represents signin or signup:
class SecondViewController: UIViewController {
//...
var shouldBehavesAsLogin = false
// ...
}
thus you could determine what is the value that should be assigned to it based on which button tapped, first view controller:
class FirstViewController: UIViewController {
// ...
private var isLoginTapped = false
#IBAction func signinTapped(sender: UIButton) {
isLoginTapped = true
}
#IBAction func signupTapped(sender: UIButton) {
// nothing to do here, isLoginTapped is false by default...
}
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == "MySegue"{
if let nextViewController = segue.destination as? SecondViewController {
nextViewController.shouldBehavesAsLogin = isLoginTapped
}
}
}
// ...
}
Thus all you have to do is to check the value of shouldBehavesAsLogin whether is it true to let the controller behaves as login or false to do the opposite.
Additional Tip:
If the purpose of adding IBActions for each button is just navigating to the second view controller, I would suggest to let both of the buttons to have the same IBAction, but you should let the sender to be of type UIButton instead of Any, thus you could do -for instance-:
#IBAction func aButtonTapped(sender: UIButton) {
// do the default behvior for both signin and signup (navigate to the second controller)
// signinButton is the button you tap for navigating to second controller to behaves as signin
isLoginTapped = sender === signinButton ? true : false
}
This answer assumes there is only one segue between the two view controllers. If there is more than one, you can simply use the segue identifier in prepareForSegue.
I'd handle this by using the sender parameter on either -prepare(for segue:sender:) or -performSegue(withIdentifier:sender), depending on whether you are triggering the segue directly from the button or in code.
If the buttons are triggering the segue, you can test whether the sender params is one of the two buttons concerned, and perform appropriate setup on the destination VC. If the segue is being triggered in code in an IBAction method, you could either pass through the button reference from the IBActions sender parameter, or pass some other identifying object that your prepareForSegue method is able to deal with.
Bear in mind that the target VC's views will not have loaded when prepareForSegue is called, so you may need to set some state on the target VC (e.g. a login/signup enum property) which is then used to set up the VC appropriately when its -viewDidLoad is called.

Bar button action on ViewController in ViewContainer

I have a container embedded in a ViewController with a navigation bar. The ContainerView contains another ViewController with some textfields.
When the ContainerView is first displayed, the textfields are disabled.
What I would like to do is add an edit button to the navigation bar which enables the textfields.
Basically, is it possible for a bar button item in a viewcontroller to have an action on another view controller displayed in a container?
in this case you can do a little trick
the bar button will be in the ViewController but we can store the content of the ContainerView in a variable in the first ViewController
to do that i would suggest to make the content of the ContainerView has a custom class so you would write a function in it
here is an example on how to catch the content of the ContainerView
class ViewController: UIViewController{
weak var containter: ContainerViewController!
#IBAction func menuAction(_ sender: UIBarButtonItem) {
//do what you want containter.doAction()
}
override func prepare(for segue: UIStoryboardSegue, sender: Any?){
if let vc = segue.destination as? ContainerViewController {
self.containter = vc
}
}
}
Always the case. I've been looking for an answer for hours, as soon as I ask I figure it out.
I'm not sure its the best way to do it but I just made an edit bool controller by the edit button. Then used:
var child = self.childViewControllers[0]
child.viewWillAppear(false)
This reloaded the data and if it was in edit mode enabled the textfields. Works fine!

Passing information between UICollectionViewControllers through unwind segues

I have two UICollectionViewControllers and the first one uses a push segue to get to the second one. The problem I'm having is passing information back to the first controller when the back button (the one that gets added automagically) is pressed in the second controller. I've tried using the segueForUnwindingToViewController, and canPerformUnwindSegueAction override functions, but no dice. I need to be able to access both view controllers so I can set some variables. Any ideas?
Here is an example with two view controllers. Let's say that the names of the two view controllers and ViewController and SecondViewController. Let's also say that there is an unwind segue from the SecondViewController to the ViewController. We will pass data from the SecondViewController to the ViewController. First, let's set the identifier of this segue by opening the document outline and selecting the unwind segue. Then open up the attributes inspector and set the identifier to "unwind".
SecondViewController Code:
class SecondViewController: UIViewController
{
override func prepareForSegue(segue: UIStoryBoardSegue, sender: AnyObject?) {
if let identifier = segue.identifier {
if let destination = segue.destinationViewController as? ViewController {
if identifier == "unwind" {
destination.string = "We Just Passed Data"
}
}
}
}
}
ViewController Code:
class ViewController: UIViewController {
var string = "The String That Will Be We Just Passed Data"
#IBAction func unwindSegue(segue: UIStoryBoardSegue) {
}
}
It sounds like you are trying to intercept the back button, there are many posts for this on SO, here are two:
Setting action for back button in navigation controller
Trying to handle "back" navigation button action in iOS
In practice, it is more clear to return state in closures (more modern), or delegates.

How to make a button to do some operation or change to another view?

help me please. how to make a button to do some operation or change to another view? I want that by pressing on it, commands were complete then need that moved on another view. please tell me how else to do to another kind in which a transition is updated when you press the button, all the same. And there were set data from datamodel
#IBAction func addNew(sender: AnyObject) {
let entity = NSEntityDescription.entityForName("Items", inManagedObjectContext:managedObjectContext!)
var item = Items(entity: entity!, insertIntoManagedObjectContext:managedObjectContext)
// I make the init from row coredata
item.titleIt = titleItem.description
item.textIt = textViewItem.description
var error: NSError?
managedObjectContext?.save(&error)
// MasterViewController.setValue(Items(), fromKey: "titlIt")
}
Add this at the end of your method:
let viewControllerToGoTo = ClassNameOfViewController()
self.presentViewController(viewController, animated: true, completion: nil)
Note: You may need to instantiate the view controller you want to present in a different way than just (). For example, you may want to load a view controller defined in a nib or storyboard.
To move to another view controller, you write these lines:
var viewController = ViewControllerNew()
self.presentViewController(viewController, animated: true, completion: nil)
But if you want to pass data to another view, I'd recommend using this method instead:
In your storyboard, select the view controller and drag from the blue-outlined yellow square at the top of the view controller to another view controller. A popup will appear, showing a list of segues. Select the item named 'Show'. Segues are placeholders for presenting view controllers -- you can call them at any time in your program. Select the segue, and under the menu on the right hand side type a name, for example 'toOtherScreen' into the text field labeled 'Identifier'. This will let you call the segue from a specific name.
Now go back to your IBAction for the button, and type this:
self.performSegueWithIdentifier("toOtherScreen", sender: self)
This will transition to the other screen. But what if you want to pass data to a screen, or do something when a segue is about to happen? Luckily for you, UIViewController class has a method named 'prepareForSegue', as shown below:
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if segue.identifier == "toOtherScreen" {
println("yes")
}
}
In this, we check if the segue has an identifier of "toOtherScreen", and if so, print "yes" to the logs. Now, to pass data to another view controller, it is a little more tricky. In the other view controller file, add a variable at the start of the class:
class OtherViewController: UIViewController {
var dataPassed: String = ""
override func viewDidLoad() {
super.viewDidLoad()
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
}
}
And in your prepareForSegue method in the main view controller, type this:
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if segue.identifier == "toOtherScreen" {
let newViewController = segue.destinationViewController as OtherViewController()
newViewController.dataPassed = "NEW DATA"
}
}
Now it will change the variable named dataPassed in OtherViewController to 'NEW DATA'. You can see how you can achieve a lot through this simple way of passing data to other view controllers.
Hope I helped.

Modifing one variable from another view controller swift

I am developing an app in Swift that, in gist, tells people the price of Bitcoin in various currencies. To select the currency, the user chooses from a list in a view controller with a UITableView. This is currencyViewController, and it is presented from my main screen, viewController.
What I want to happen is that, when the user dismisses currencyViewController, it passes a string to a UIButton in the main viewController.
Here's the prepareForSegue function that should pass the data:
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject!) {
if (segue.identifier == "presentCurrency") {
currencySelector.setTitle("\currencySelected", forState: UIControlState.Normal)
}
}
CurrencySelector is a UIButton in the main viewController, and currencySelected is a variable in the second view controller, currencyViewController.
It gives the error "Invalid Escape Sequence In Literal"
So, I've narrowed it down to one of two issues:
The variables from viewController can't be "seen" from currencyViewController. If so, how can I modify the text of CurrencySelector from CurrencyViewController?
For some reason, when the user exits the pushed CurrencyViewControler, prepareForSegue isn't called.
What is going on here? Thanks, and apologies - I am but a swift newbie.
2 - "prepareForSegue" is called when you push a new view controller via the segue, but not when you dismiss it. No segue is called upon dismissal.
1 - A good way to do this would be the delegate pattern.
So the main view controller would be the delegate for the currencyViewController, and would receive a message when that controller is dismissed.
In the start of the currencyViewController file you prepare the delegate:
protocol CurrencyViewControllerDelegate {
func currencyViewControllerDidSelect(value: String)
}
and you add a variable to the currencyViewController:
var delegate : CurrencyViewControllerDelegate?
Now, the mainViewController has to conform to that protocol and answer to that function:
class MainViewController : UIViewController, CurrencyViewControllerDelegate {
//...
func currencyViewControllerDidSelect(value: String) {
//do your stuff here
}
}
And everything is prepared. Last steps, in prepareForSegue (MainViewController), you will set the delegate of the currencyViewController:
var currencyVC = segue.destinationViewController as CurrencyViewController
currencyVC.delegate = self;
And when the user selects the value in currencyViewController, just call that function in the delegate:
self.delegate?.currencyViewControllerDidSelect("stuff")
A bit complex maybe, but it's a very useful pattern :) here is a nice tutorial with more info if you want it:
http://www.raywenderlich.com/75289/swift-tutorial-part-3-tuples-protocols-delegates-table-views
You have to use the parantheses to eval variables in strings, i.e. println("\(currencySelected)")
To access variables in the second view controller (the one which is the destination of the segue) you have to get a reference to it:
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject!) {
if (segue.identifier == "presentCurrency") {
let currencyViewController = segue.destinationViewController as CurrencyViewController // the name or your class here
currencySelector.setTitle("\(currencyViewController.currencySelected)", forState: UIControlState.Normal)
}
}

Resources