prepareForSegue not being called inside UIBarButtonItem selector - ios

Here is my code where I register the UIBarButtonItems and its Selector Function.
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
var edit = UIBarButtonItem(title: "Edit", style: UIBarButtonItemStyle.Plain, target: self, action: Selector("editTruck"))
let delete = UIBarButtonItem(title: "Delete", style: UIBarButtonItemStyle.Plain, target: self, action: "deleteTruck")
let menu = UIBarButtonItem(image: UIImage(named: "menu"), style: UIBarButtonItemStyle.Plain, target: self.revealViewController(), action: "rightRevealToggle:")
self.navigationItem.rightBarButtonItems = [menu,delete,edit]
self.title = truckName.text
self.view.addGestureRecognizer(self.revealViewController().panGestureRecognizer())
self.view.addGestureRecognizer(self.revealViewController().tapGestureRecognizer())
}
func editTruck(){
println("insdie edittruck")
self.performSegueWithIdentifier("editTruck", sender: self)
func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?){
println("inside prepare")
if segue.identifier == "editTruck"{
let vc = segue.destinationViewController as? UINavigationController
let topView = vc?.topViewController as! AddTruckViewController
topView.truckNameValue = name.text!
topView.totalFuelupsValue = totalFuelups.text!
topView.totalDistanceTrackedValue = totalDistanceTracked.text!
topView.truckYearValue = truckYear.text!
topView.truckMakeValue = truckMake.text!
topView.truckModelValue = truckModel.text!
topView.truckImagevalue = truckImage.image!
topView.engineMakeValue = engineMake.text!
topView.engineModelValue = engineModel.text!
topView.horsePowerValue = horsePower.text!
topView.axleValue = axle.text!
topView.trailerTypeValue = trailerType.text!
topView.steerTireMakeValue = steerTireMake.text!
topView.steerTireModelValue = steerTireModel.text!
topView.steerTireSizeValue = steerTireSize.text!
topView.driveTireMakeValue = driveTireMake.text!
topView.driveTireModelValue = driveTireModel.text!
topView.driveTireSizeValue = driveTireSize.text!
topView.transmissionMakeValue = transmissionMake.text!
topView.transmissionModelValue = transmissionModel.text!
topView.distanceUnitValue = distanceUnit.text!
topView.volumeUnitValue = volumeUnit.text!
}
}
}
In IB I Control Dragged from the TruckSpecsViewController (the yellow icon at the top since my buttons are created programmatically),where my above code is from, to the Scene where I want to segue to. I added the identifier to that segue of "editTruck". In the code above the performSegueWithIdentifier works but the prepareForSegue doesnt. No errors or anything it just never gets called.
Any help would be much appreciated.

Move the prepareForSegue:sender method to the same level as your editTruck method in your View Controller. The change of scope will fix your problem.
iOS automatically calls the prepareForSegue:sender method on your View Controller either in response to a segue in a Storyboard or by calling performSegueWithIdentifier:sender: in code.
You never call prepareForSegue:sender yourself; you just implement this method in your View Controller.

Related

UIBARBUTTON back action

let backButton = UIBarButtonItem(title: "Back", style: UIBarButtonItemStyle.plain, target: self, action: Selector(("HomeTabController")))
self.navigationItem.leftBarButtonItem = backButton
The above code is the creation of button in navigationController but I can create a button cannot write a specific view controller to open.
I have tried with popViewController and popToRootViewController action, need a specific code for opening a particular viewController in swift, with the help of the particular viewController storyboard id and viewcontrollername.
You need to add func name in #selctor() (Swift 4 version)
let backButton = UIBarButtonItem(title: "Back", style: .plain, target: self, action: #selector(goToViewController(_:)))
self.navigationItem.leftBarButtonItem = backButton
You need to create a func.
#objc func goToViewController(_ sender: UIBarButtonItem) {
//write code here to open a view controller
let storyboard = "Main"
let viewControllerIdentifier = "HomeVC"
let viewController = UIStoryboard(name: storyboard, bundle: nil).instantiateViewController(withIdentifier: viewControllerIdentifier) as! HomeVC
//push/present "viewController"
}
in this code just replace ChatVC name to your viewcontroller name
#objc func goToViewController(_ sender: UIBarButtonItem) {
for controller in self.navigationController!.viewControllers as Array {
if controller.isKind(of: ChatVC.self) {
self.navigationController!.popToViewController(controller, animated: true)
break
} else {
self.navigationController?.popViewController(animated: true)
}
}
}

Programmatically segue from UIBarButtonItem

I have three view controllers, all with two buttons each on the right and left sides of the navigation bar, as seen below on one of them.
I'm creating these buttons programatically, and instead of writing the code in each respective view controller (VC) I decided to write a Helper class that creates the buttons.
// Note: I am using FontAwesome as a third-party library.
class Helper: NSObject {
static func loadNavBarItems(vc: UIViewController) {
let profileButton = UIBarButtonItem()
let addButton = UIBarButtonItem()
let attributes = [NSFontAttributeName: UIFont.fontAwesome(ofSize: 20)] as [String: Any]
profileButton.setTitleTextAttributes(attributes, for: .normal)
addButton.setTitleTextAttributes(attributes, for: .normal)
profileButton.title = String.fontAwesomeIcon(name: .userCircle)
addButton.title = String.fontAwesomeIcon(name: .plus)
vc.navigationItem.leftBarButtonItem = profileButton
vc.navigationItem.rightBarButtonItem = addButton
}
func segueToProfile(vc: UIViewController) { // I need help here. }
}
I then call Helper.loadNavBarItems(vc: self) from each VC's viewDidLoad().
What I'm trying to do now is to trigger a segue when one of the buttons is pressed (let's assume it's the profile button). So, I need to define profile.action. So, in the Helper class, I have to write a function segueToProfile that takes a view contoller (vc) and runs performSegueWithIdentifier.
The problem is, I'm not fully understanding how to pass in different types of parameters through selectors, and I may be bad at Googling but I cannot find any questions that are close enough to mine for me to understand how to achieve this.
Many thanks in advance for your help.
For reference, this is the structure of my Storyboard.
EDIT: As shown in the storyboard structure screenshot, I've already created a segue from each of the three view controllers to the destination view controller.
To create barButtonItem:
navigationItem.rightBarButtonItem = UIBarButtonItem(title: "😱", style: .plain, target: self, action: #selector(ProfileButtonTapped))
To create action and segue for barButtonItem:
func ProfileButtonTapped() {
print("Button Tapped")
performSegue(withIdentifier: "YourSegueIdentifierName", sender: self)
//If you want pass data while segue you can use prepare segue method
}
Note : To perform segue you have to give segue identifier name from your storyboard.
Output:
Updated:
If you want to connect your destVC without segue you can use below method:
Note: To use below method you have to set storyBoard Id in identity inspector.
let storyboard = UIStoryboard(name: "Main", bundle: nil)
let DestVC = storyboard.instantiateViewController(withIdentifier: "DestVcName") as! DestVcName //UINavigationController
self.present(DestVC, animated: true, completion: nil)
i don't know if i understand your problem, but for passing data between viewControllers(embedded in a UINavigationController in your case) using segue, you can do it in:
override func prepare(for segue: UIStoryboardSegue, sender: Any?){
if(segue.identifier == "yourIdentifier"){
let navPreview : UINavigationController = segue.destination as! UINavigationController
let preview : YourViewController = navPreview.viewControllers[0] as! YourViewController
}}
To add an action to a UIBarButton you should use one of its initializers.
For example
let profileButton = UIBarButtonItem(title: "Your title", style: .done, target: self, action: #selector("Call your function to push View controller"))
Instead of title , you can also set an Image to that button.
You can create barButtonItems with selectors :
let leftBarButton = UIBarButtonItem(image: image, landscapeImagePhone: image, style: UIBarButtonItemStyle.bordered, target: self, action: #selector(didPressLeftButton))
Where the didPressLeftButton is a function :
func didPressLeftButton(){
print("Did press left button")
}

Create a custom UINavigationcontroller class

I have done the following customisation to my embedded UINavigationcontroller. I've done this in the view controller of the view that will show up as first.
However I'm trying to clean it up so that I don't have this all in my UIView class by creating a separate class that will take care of this. The code I'm currently using
self.navigationController?.navigationBar.setBackgroundImage(UIImage(named: "navigation.background"), for: .default)
let backButton = UIImage(named: "Back.button")?.withRenderingMode(.alwaysOriginal)
let backButtonHigh = UIImage(named: "Back.button.highlighted")?.withRenderingMode(.alwaysOriginal)
self.navigationController?.navigationBar.backIndicatorImage = backButton
self.navigationController?.navigationBar.backIndicatorTransitionMaskImage = backButtonHigh
self.navigationItem.backBarButtonItem = UIBarButtonItem(title: "", style: .plain, target: nil, action: nil)
What I've tried to do is extend the UInavigationcontroller in a new class like this
class RSRNavigationController: UINavigationController{
override func viewDidLoad() {
super.viewDidLoad()
self.navigationController?.navigationBar.setBackgroundImage(UIImage(named: "navigation.background"), for: .default)
let backButton = UIImage(named: "Back.button")?.withRenderingMode(.alwaysOriginal)
let backButtonHigh = UIImage(named: "Back.button.highlighted")?.withRenderingMode(.alwaysOriginal)
self.navigationController?.navigationBar.backIndicatorImage = backButton
self.navigationController?.navigationBar.backIndicatorTransitionMaskImage = backButtonHigh
self.navigationItem.backBarButtonItem = UIBarButtonItem(title: "", style: .plain, target: nil, action: nil)
}
}
this doesn't work. It will run without problems but it won't actually do anything.
I've also tried to do the following
class RSRNavigationController: UINavigationBar{
override func draw(_ rect: CGRect) {
super.draw(rect)
self.setBackgroundImage(UIImage(named: "navigation.background"), for: .default)
let backButton = UIImage(named: "Back.button")?.withRenderingMode(.alwaysOriginal)
let backButtonHigh = UIImage(named: "Back.button.highlighted")?.withRenderingMode(.alwaysOriginal)
self.backIndicatorImage = backButton
self.backIndicatorTransitionMaskImage = backButtonHigh
//self.backItem = UIBarButtonItem(title: "", style: .plain, target: nil, action: nil)
}
However I can't seem to set the title for the back button.
Does anyone know how to fix this?
Your problem lies here, when you reference navigationController INSIDE your custom navigationController class
Instead of doing
self.navigationController?.navigationBar.backIndicatorImage = backButton
do this
self.navigationBar.backIndicatorImage = backButton
Reason?
Because when you extend your custom class by UINavigationController, it becomes a navigationController itself. And by doing self.navigationController you are telling your app to look for a navigationController within which your custom navigationCOntroller resides. Ofcourse such a nav controller does not exist because your custom navController is the main or the top navController of the app. So just remove the self.navigationController part from your custom class, the rest of the code that you have written in your viewDidLoad should work good.
If you still have any questions feel free to ask
You do not change these properties in the navigation controller itself, you change it in the viewController that is embedded inside a navigation controller.
These customization has to be done in a parent ViewController of your view controllers.
This Answer has more info:
https://stackoverflow.com/a/16913435/4004429
if you just want to custom the backButton of the navigationBar,you can add this code in your child view controller :
func setupLeftBarItem() -> Void {
let originalImage = UIImage.init(named: "leftBatItem")?.withRenderingMode(.alwaysOriginal)
let leftBarItem = UIBarButtonItem.init(image: originalImage, style: .done, target: self, action: #selector(leftBarButtonItemDidTouch))
navigationItem.leftBarButtonItem = leftBarItem
}
func leftBarButtonItemDidTouch() -> Void {
_ = navigationController?.popViewController(animated: true)
}

performSegue with programmatically added Navigation button

I am trying to customize a Navigation bar button item programmatically... I am just having some issues here which I am sure is an easy fix. I want to make it the default Add button for now, but also in the future will want to make the bar button item a custom icon I create. so I guess I would like to know both ways how to programmatically change a navigation bar button to default styles and custom icons...thanks!
override func viewDidAppear(animated: Bool) {
let rightbutton = UIBarButtonItem(title: "+", style: UIBarButtonItemStyle.Plain, target: self, action: "uploadButtonClicked")
navigationItem.rightBarButtonItem = rightbutton
}
Here is how you would do it with the default add button:
let button = UIBarButtonItem(barButtonSystemItem: UIBarButtonSystemItem.Add, target: self, action: "uploadButtonClicked")
self.navigationItem.rightBarButtonItem = button
Here is how you would programmatically add a custom image:
let customImage = UIImage(named: "customButtonImage")
let customButton = UIBarButtonItem(image: customImage, style: UIBarButtonItemStyle.Plain, target: self, action: "uploadButtonClicked:")
self.navigationItem.rightBarButtonItem = customButton
To perform the segue, you can do this:
#IBAction func uploadButtonClicked(sender: UIBarButtonItem) {
performSegueWithIdentifier("segueIdentifier", sender: self)
}
Or, if you want to go to another storyboard from there, then your IBAction will look like this:
#IBAction func uploadButtonClicked(sender: UIBarButtonItem) {
let storyboard = UIStoryboard(name: "YourStoryboard", bundle: nil)
let nc = storyboard.instantiateInitialViewController() as! UINavigationController
let vc = nc.viewControllers.first as! YourViewController

Custom UIBarButtonItem in UISplitViewController doesn't respond to clicks (iPhone)

I'm trying to customize the appearance of a UIBarButtonItem on a UISplitViewController divided into two UINavigationController's (the detail and master views), but keep hitting a brick wall. I first followed the advice here, but have been unable to achieve the desired results.
If if I implement the back button in the viewDidLoad method of my Detail View Controller in this way:
if let svc = splitViewController {
navigationItem.leftBarButtonItem = svc.displayModeButtonItem()
}
I get the default 'Back' button that navigates back to Master View controller. But if I try to customize the button using the following code:
if let svc = splitViewController {
let searchButton = UIBarButtonItem(
image: UIImage(named: "magnifying-glass"),
style: UIBarButtonItemStyle.Plain,
target: svc.displayModeButtonItem().target,
action: svc.displayModeButtonItem().action
)
navigationItem.leftBarButtonItem = searchButton
}
I get the desired icon in the navbar but it does nothing when clicked. I've debugged the action and target in the console and for both the action is "_triggerDisplayModeAction:" and the controller is an instance of the UISplitViewController.
Any ideas on what's going on here?
i suggest you to create and use your custom UIBarButtonItem in prepareForSeque in master view controller. split view controller by default will create new instance of your detail view controller!!! ignore the part with iPhone ios7support, that is another story :-) https://github.com/op183/MasterDetailDemo
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if segue.identifier == "showDetail" {
if let indexPath = self.tableView.indexPathForSelectedRow() {
let object = objects[indexPath.row] as String
if let navController = (segue.destinationViewController as? UINavigationController) {
let controller = navController.topViewController as DetailViewController
controller.detailItem = object
let defaultBarButton = splitViewController?.displayModeButtonItem()
let searchButton = UIBarButtonItem(
image: UIImage(named: "magnifying-glass"),
style: UIBarButtonItemStyle.Plain,
target: defaultBarButton.target,
action: defaultBarButton.action
)
controller.navigationItem.leftBarButtonItem = searchButton
controller.navigationItem.leftItemsSupplementBackButton = true
} else {
// iPhone ios7support
(segue.destinationViewController as DetailViewController).detailItem = object
}
}
}
}

Resources