Get title of a navigation bar button item in swift? - swift4

I am not able to get navigation bar button item, when I created action outlet.Here is my code
#IBAction func rightBarButtonItemDidTap(_ sender: Any) {
print(sender.title)
}
but title is not available.

Try this
#IBAction func rightBarButtonItemDidTap(_ sender: Any) {
let barButton = sender as? UIBarButtonItem
if let title = barButton?.title {
print(title)
}
}

Related

How to hide an action button in Swift?

I try to make a button invisible after pressing it. The Connection is an action and not an outlet, because pressing the button will call additional code.
#IBAction func startGame(_ sender: Any) {
print("The game starts...")
}
This does not work, because the button is an action and not an outlet:
startGame.isHidden = true
Is there another way to make an action button invisible and therefore not clickable?
Just create an IBOutlet of the same button and set its isHidden property to true once it's tapped.
#IBAction func startGame(_ sender: Any) {
startGameButton.isHidden = true
}
You can hide button on pressed action this way
#IBAction func startGame(_ sender: Any) {
let pressedButton : UIButton = sender as! UIButton
pressedButton.isHidden = true;
}
You can rewrite your code a little bit as Pratik suggested, so it will look like this:
#IBAction func startGame(_ sender: UIButton) {
sender.isHidden = true
/*
remove button at all from the parent view.
sender.removeFromSuperview()
*/
print("The game starts...")
}

How do I pass data from a UIViewController to UITabBarController?

In UIViewController:
class ViewController2: UIViewController {
var points = 0
var pressed = false
#IBOutlet weak var label: UILabel!
#IBAction func slider(_ sender: UISlider) {
number = Int(sender.value)
label.text = String(number)
}
#IBAction func submitbutton(_ sender: UIButton) {
pressed = true
}
}
I am trying to do something in a TabBarController if a button in a UIViewController is pressed and also add a number to the number in another TabBarConroller.
Image 1: This shows the connection between my ViewControllers.
Image 2: This shows the first two ViewControllers.)
Image 3: This shows the third and fourth ViewController
Here is my storyboard. I've put a few words to describe what I am trying to do in the images. Please tell me if you need a clearer description. Thank you!
If the ViewController is a child of the UITabBarController that you want to access, you can simply use tabBarController property of the UIViewController, e.g., use this to change selected controller to the first one:
#IBAction func submitbutton(_ sender: UIButton) {
pressed = true
self.tabBarController?.selectedIndex = 0
}
So let's say that you have a custom UITabBarController subclass, e.g.:
class CustomTabBarController: UITabBarController {
func acceptData(points: Int) {
print(">>> Accepted: \(points)")
// or do anything you need to do with it
}
}
Then you can pass it data as follows:
#IBAction func submitbutton(_ sender: UIButton) {
pressed = true
if let customTabController = self.tabBarController as? CustomTabBarController {
customTabController.acceptData(points: self.points)
}
}
UPDATE
Since it seems that the current VC is presented by one of the tabBarController child controllers, you will have to access it through the self.presentingViewController:
#IBAction func submitbutton(_ sender: UIButton) {
pressed = true
if let customTabController = self.presentingViewController?.tabBarController as? CustomTabBarController {
customTabController.acceptData(points: self.points)
}
}
UPDATE 2
Your screenshot are of a very poor quality, your explanation of the problem would require a clarification too, since it is really hard to understand what you try to do. So after the whole discussion in comments I guess this is it:
#IBAction func submitbutton(_ sender: UIButton) {
pressed = true
if let tabController = self.presentingViewController?.tabBarController,
let viewController3 = tabController.viewControllers?.filter({ $0 is ViewController3 }).first {
viewController3.acceptData(points: self.points)
}
}
You can pass data as normally
let vc:HomeVC = ApiUtillity.sharedInstance.getCurrentLanguageStoryboard().instantiateViewController(withIdentifier: "HomeVC") as! HomeVC
vc.tempCategoryArray = CategoryArray
self.navigationController?.pushViewController(vc, animated: true)
In your TabBarController class, take a variable say variableToBeSet
class TabBarController: UITabBarController
{
var variableToBeSet: Int = 0 // This is just an example. You can change it as per requirement.
// Rest of class implementation
}
Now in your ViewController :
#IBAction func submitbutton(_ sender: UIButton) {
pressed = true
let tabControllerInstance = self.tabBarController as! TabBarController
tabControllerInstance.variableToBeSet = localVariable // The value which you want to assign
}

Open a storyboard view with a stackview button in Swift 3 and Xcode

I have three views in my storyboard: MainViewController, EditViewController and PatchViewController.
In my Main view I've added a Horizontal Stack View-object which has its own class (class FieldController: UIStackView) where I add three buttons programatically.
Depending on some dynamic values, clicking on one of these buttons should open either the Edit or Patch-view which also should have access to an id that corresponds to what button clicked.
How can I achieve this?
First, you need to create segues in your storyboard from main controller to your additional controllers and set different identifier for each segue. In my example I'm using EditSegueIdentifier and PatchSegueIdentifier
Then in your main controller:
//connect IBActions to each button, or your buttons may have one action to connect to, but have also different tags, like below:
#IBAction func buttonAction(_ sender: UIButton) {
//You can send an ID as Int for example, to catch them in prepareForSegue method.
//You can send any values or objects as sender,
//also it can be a tag of clicked button, whatever you want.
switch sender.tag{
case 1:
performSegue(withIdentifier: "EditSegueIdentifier", sender: YourIDForEDIT)
case 2:
performSegue(withIdentifier: "PatchSegueIdentifier", sender: YourIDForPATCH)
default: break
}
}
If you are using programatically created buttons, you can make same thing inside their selector method:
func setTargets(){
let selector = #selector(buttonAction(_:))
yourFirstButton.tag = 1
yourFirstButton.addTarget(self, action: selector, for: .touchUpInside)
yourSecondButton.tag = 2
yourSecondButton.addTarget(self, action: selector, for: .touchUpInside)
}
func buttonAction(_ sender: UIButton){
switch sender.tag{
case 1:
performSegue(withIdentifier: "EditSegueIdentifier", sender: YourIDForEDIT)
case 2:
performSegue(withIdentifier: "PatchSegueIdentifier", sender: YourIDForPATCH)
default: break
}
}
Then we need to prepare values to send to additional controllers
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
//check segue identifier for sending values to destination controller
if segue.identifier == "EditSegueIdentifier", let editID = sender as? Int {
let destination = segue.destination as? EditViewController
destination?.id = editID
}
if segue.identifier == "PatchSegueIdentifier", let patchID = sender as? Int {
let destination = segue.destination as? PatchViewController
destination?.id = patchID
}
}
==============EDIT==================
The protocol
protocol YourStackViewDelegate {
func performButtonAction(with index: Int) //or you can send anything else (e.g. ID, objects)
}
Then in your StackViewClass
class YourStackViewClass {
//make optional var for delegate instance
var delegate: YourStackViewDelegate?
func setTargets(){
let selector = #selector(buttonAction(_:))
yourFirstButton.tag = 1
yourFirstButton.addTarget(self, action: selector, for: .touchUpInside)
yourSecondButton.tag = 2
yourSecondButton.addTarget(self, action: selector, for: .touchUpInside)
}
func buttonAction(_ sender: UIButton){
//call the method from the protocol
delegate?.performButtonAction(with: sender.tag)
}
}
In your view controller
override func viewDidLoad() {
super.viewDidLoad()
yourStackView.delegate = self
}
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
//check segue identifier for sending values to destination controller
if segue.identifier == "EditSegueIdentifier", let editID = sender as? Int {
let destination = segue.destination as? EditViewController
destination?.id = editID
}
if segue.identifier == "PatchSegueIdentifier", let patchID = sender as? Int {
let destination = segue.destination as? PatchViewController
destination?.id = patchID
}
}
Then add an extension of you view controller with the delegate
extension YourViewController: YourStackViewDelegate {
func performButtonAction(with index: Int) {
switch index{
case 1:
performSegue(withIdentifier: "EditSegueIdentifier", sender: YourIDForEDIT)
case 2:
performSegue(withIdentifier: "PatchSegueIdentifier", sender: YourIDForPATCH)
default: break
}
}
}

How to send multiple variables in one single sender?

I'm trying to send multiple variables in one single sender to show it in the Viewcontroller that it's connected to a segue named menuENG. I have five buttons and each button should send different information because is a dictionary and each button is a word. But I want to do this thru one sender. I tried the following code to make it but it is not working.
p.s.: I tried making an array but Xcode goes crazy.
#IBAction func abstractionENG(sender:UIButton) {
return perfomanceWithIdentifier("menuENG",sender:nil)
}
I think you can send the dictionary and there is something wrong with this line return perfomanceWithIdentifier("menuENG",sender:nil)
Anyway you can seperatly identify which button is clicked by tag and create dictionary on base of clicked button now you can send the complete dictionary to the sender.
#IBAction func abstractionENG(sender:UIButton) {
var dictSendData:[String:Any] = [:]
if sender == btn1
{
dictSendData.updateValue("abc", forKey: "key1")
dictSendData.updateValue("pqr", forKey: "key2")
}
else if sender == btn2
{
dictSendData.updateValue("xyz", forKey: "key1")
dictSendData.updateValue("123", forKey: "key2")
}
else
{
dictSendData.updateValue("123", forKey: "key1")
dictSendData.updateValue("abc", forKey: "key2")
}
self.performSegue(withIdentifier:"menuENG", sender: dictSendData)
}
1- assign segue action to IBAction function - assign tag id to ever button
you have already implemented it .
2- your IBAction function should run another function to run performSegue function
example :
self.performSegue(withIdentifier: "openAnotherViewController",sender: sender)
3- go to destination view Controller and create reciver variables "Maybe you can use optionals " .
var receiverInt :Int = 0
var receiverInt2 :Int = 0
3- go to the source view Controller and pass variables
// MARK: - Navigation
// In a storyboard-based application, you will often want to do a little preparation before navigation
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
// Get the new view controller using segue.destinationViewController.
// Pass the selected variable/object to the new view controller .
if segue.identifier == "openAnotherViewController" {
let destinationController = segue.destination as! OtherViewControllerClass Name
// identify button by tag number
if (sender as! UIButton).tag == 200 {
destinationController.receiverInt = self.sourceInt
}else{
destinationController.receiverInt2 = self.sourceInt2}
}
}
Thank you everyone for the help fixed the issue by this way >
class MainViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
}
/* The following functions containts a group of conditionals which will change the scene depending of the IBAction selected */
#IBAction func abstractionENG(sender: UIButton) {
let data = [DiccioModel.abstraction().nameEng,DiccioModel.abstraction().descriptionEng,DiccioModel.abstraction().linkEng]
performSegueWithIdentifier("menuENG", sender: data)
}
#IBAction func webBrowserENG(sender: UIButton) {
let data = [DiccioModel.webBrowser().nameEng,DiccioModel.webBrowser().descriptionEng,DiccioModel.webBrowser().linkEng]
performSegueWithIdentifier("menuENG", sender: data)
}
#IBAction func latencyENG(sender: UIButton) {
let data = [DiccioModel.latency().nameEng,DiccioModel.latency().descriptionEng,DiccioModel.latency().linkEng]
performSegueWithIdentifier("menuENG", sender: data)
}
#IBAction func conditionalENG(sender: UIButton) {
let data = [DiccioModel.conditional().nameEng,DiccioModel.conditional().descriptionEng,DiccioModel.conditional().linkEng]
performSegueWithIdentifier("menuENG", sender: data)
}
#IBAction func operatingSystemENG(sender: UIButton) {
let data = [DiccioModel.os().nameEng,DiccioModel.os().descriptionEng,DiccioModel.os().linkEng]
performSegueWithIdentifier("menuENG", sender: data)
}
#IBAction func abstractionESP(sender: UIButton) {
let data = [DiccioModel.abstraction().nameEsp,DiccioModel.abstraction().descriptionEsp,DiccioModel.abstraction().linkEsp]
performSegueWithIdentifier("menuESP", sender: data)
}
#IBAction func webBrowserESP(sender: UIButton) {
let data = [DiccioModel.webBrowser().nameEsp,DiccioModel.webBrowser().descriptionEsp,DiccioModel.webBrowser().linkEsp]
performSegueWithIdentifier("menuESP", sender: data)
}
#IBAction func latencyESP(sender: UIButton) {
let data = [DiccioModel.latency().nameEsp,DiccioModel.latency().descriptionEsp,DiccioModel.latency().linkEsp]
performSegueWithIdentifier("menuESP", sender: data)
}
#IBAction func conditionalESP(sender: UIButton) {
let data = [DiccioModel.conditional().nameEsp,DiccioModel.conditional().descriptionEsp,DiccioModel.conditional().linkEsp]
performSegueWithIdentifier("menuESP", sender: data)
}
#IBAction func operatingSystemESP(sender: UIButton) {
let data = [DiccioModel.os().nameEsp,DiccioModel.os().descriptionEsp,DiccioModel.os().linkEsp]
performSegueWithIdentifier("menuESP", sender: data)
}
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if(segue.identifier == "menuENG") || (segue.identifier == "menuESP"){
if let destinationViewController = segue.destinationViewController as? DefinitionViewController{
if let data = sender as? Array<String>{
destinationViewController.tittle = data[0]
destinationViewController.def = data[1]
destinationViewController.link = data[2]
}
}
}
}
PS: note this code is connected to the DefinitionViewController ( Controller of the view) and to a model. ( project was made by M.V.C way).
Again Thx everyone for your help. hope the code help other people in the future.

swift 3 popover with Xcode

i have an nstableview with custom cells.
each cell has a nsbutton.
now i would like to create an popover to another view controller, when the button was pressed.
what i have done?
i create a segue connection between my nstableview and the popover view controller and give it an identifier.
in my custom cell i created i IBOutle action for the nsbutton:
#IBAction func actionButtont(_ sender: Any) {
let vcTable = NSStoryboard(name: "Main", bundle: nil).instantiateController(withIdentifier: "vcTable ") as! TableView
vcTable.startSegue(text: "Test")
}
and in my TableViewController:
var text = String()
func startSegue(text:String) {
text = text
self.performSegue(withIdentifier: "Popover", sender: self)
}
override func prepare(for segue: NSStoryboardSegue, sender: Any?) {
let vc = segue.destinationController as! Popover
vc.text = text
}
My "text String" will passed successfully.
but me segue will not work, because my app crashes before with this error:
[General] -[NSPopover showRelativeToRect:ofView:preferredEdge:]: view has no window. You must supply a view in a window.
what did I wrong?