Passing data between view controllers with a UIAlertAction in Swift - swift2

I have a tableView, and when the user taps a cell, it opens an alert box with the options "Close" and "Search". The handler for "Search" is shown below as func searchSongAction.
This presents a new viewcontroller (embedded in a Nav Bar) that searches the song online. In this new viewcontroller, Search, there are 2 functions: one searches the song currently playing and the other searches the song that the user asked to search from the tableView alert.
I am trying to pass the data from the cell into the Search class, but I keep coming up short. I feel like what I have is correct, but that is obviously not he case.
Any ideas?
Ask me if you need any more information.
History.swift
func searchSongAction(alert: UIAlertAction!) {
let vc = self.storyboard?.instantiateViewControllerWithIdentifier("Search") as! Search
let navigationController = UINavigationController(rootViewController: vc)
self.presentViewController(navigationController, animated: true, completion: nil)
}
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
let destinationNavigationController = segue.destinationViewController as! UINavigationController
let targetController = destinationNavigationController.topViewController as! Search
targetController.searchType = "Previous"
targetController.songNowText = self.songToSearch
targetController.artistNowText = self.artistToSearch
}
Search.swift
class Search: UIViewController {
var songNowText = ""
var artistNowText = ""
var searchType = ""
override func viewDidLoad() {
super.viewDidLoad()
if searchType == "Previous" {
searchSongPrevious()
} else {
searchSongNow()
}
}
}

You're not actually performing a Segue from your searchSongAction: function, so I'm guessing that prepareForSegue:sender: isn't actually being called and therefore the setup is not running.
Try assigning searchType, songNowText and artistNowText on vc inside of searchSongAction::
func searchSongAction(alert: UIAlertAction!) {
let vc = self.storyboard?.instantiateViewControllerWithIdentifier("Search") as! Search
//Setup the properties
vc.searchType = "Previous"
vc.songNowText = self.songToSearch
vc.artistNowText = self.artistToSearch
let navigationController = UINavigationController(rootViewController: vc)
self.presentViewController(navigationController, animated: true, completion: nil)
}
As a side note, typically you'll want to call super's implementation of a function when overriding it (you have neglected to do this in prepareForSegue:sender:)

Related

Swift 3 - Saving text when a user touches outside of a UITextField

In Swift 3, I need to detect if the user touches outside of a UITextField, then check that a particular UITextField is the sender, and then save the text. I have been trying to do this with Notification Center I have found examples in Swift 2, but I am struggling to implement the correct syntax for Swift 3.
let notificationName = Notification.Name("UITextFieldTextDidChange")
NotificationCenter.default.addObserver(self, selector: #selector(self.textFieldDidChange), name: notificationName, object: nil)
NotificationCenter.default.post(name: notificationName, object: nil)
func textFieldDidChange(sender: AnyObject) {
if let notification = sender as? NSNotification,
let textFieldChanged = notification.object as? UITextField
where textFieldChanged == self.myTextField {
storedText = myTextField.text!
}
}
UPDATE
I have found a slightly different way of doing this which works for me:
myTextField.addTarget(self, action: #selector(didChangeText(textField:)), for: .editingChanged)
func didChangeText(textField: UITextField) {
if let textInField = myTextField.text {
myTextField.text = textInField
storedText = myTextField.text!
}
}

Swift delegate for 2 container views to communicate

In the storyBoard "parent" scene with its parentVC.swift, there are 2 containerVC with embedded segues with their containerVC.swift for each.
In container1, a button action calls the parent custom method.
(self.parentViewController as? parentVC)?.parentCustomFunc()
which call container2 custom method.
func parentCustomFunc(){
self.container2.customFunc()
}
I read a lot but yet to understand how to apply the use of delegate in this case.
here is my segue block as recorded in parentVC.swift
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if let container1VC = segue.destinationViewController as? Cont_1 {
self.container1 = container1VC
} else if let topVC = segue.destinationViewController as? TopVC {
self.container2 = container2VC
}
}
Which of the containers should implement the protocol?
and which of them holds a var to it? How do I get the prepareForSegue to use the delegate?
Thanks
You should create two protocol for each ChildViewController.
Maybe like this:
protocol Child1Delegate {
func userTapOnChild1()
}
protocol Child2Delegate {
func userTapOnChild2()
}
And in each controller you can create instance:
var delegate: Child2Delegate!
var delegate : Child1Delegate!
At Parent controller you implement prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) to assign delegate to child:
//You get right identifier of segue you named on storyboard
if segue.identifier == "SegueChild1" {
let controller = segue.destinationViewController as! Child1ViewController
controller.delegate = self
}
if segue.identifier == "SegueChild2" {
let controller = segue.destinationViewController as!Child2ViewController
controller.delegate = self
}
And when you do an action from child you can call delegate notify for Parent:
#IBAction func child1ButtonIsTapped(sender: AnyObject) {
if let _delegate = delegate {
_delegate.userTapOnChild1()
}
}
Parent will implement delegate and do something need:
func userTapOnChild1() {
let alertController = UIAlertController(title: "Child1", message: "I come from child 1", preferredStyle: .Alert)
let action = UIAlertAction(title: "OK", style: .Cancel, handler: nil)
alertController.addAction(action)
self.presentViewController(alertController, animated: true, completion: nil)
}
Detail you can reference to my demo for this case: Demo

UiTextField not changing after Prepare for Segue

I am having a strange little problem when I segue to the next ViewController. I have it set up so that when I segue it should change the TextField of the next ViewController but for some reason or another it isn't. The segue works but the TextField doesn't change.
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if segue.identifier == "Edit" {
let cell = sender as! UITableViewCell
let indexPath = TaskTableViews.indexPathForCell(cell)
let itemController: TaskManager = segue.destinationViewController as! TaskManager
let nItem: List = frc.objectAtIndexPath(indexPath!) as! List
itemController.nItem = nItem
}
if (segue.identifier == "Give") {
let itemController : TaskManager = segue.destinationViewController as! TaskManager
itemController.addTaskText = "Great"
}
}
Heres the ViewDidLoad of my secondViewController..
// View Did Load
override func viewDidLoad() {
super.viewDidLoad()
if nItem != nil {
addTask.text = (nItem?.taskName)!
}
addTask.placeholder = "Title ..."
addTaskText = addTask.text!
Check that you're actually performing the segue with the relevant identifier and take a look at prepareForSegue. If it is like the code below it should work. Also, in your second ViewController you can set the text in your textField in viewDidLoad. Just make sure that the data is actually being passed from the first to the second ViewController
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if segue.identifier == "Great" {
let itemController = segue.destinationViewController as! YourDestinationViewController
itemController.someStringVariable = "Great"
}
}
In your second ViewController you can declare a variable that will get it's value during the segue and then use that variable's value to set the text of your textField, like this:
var someStringVariable: String!
override func viewDidLoad() {
super.viewDidLoad()
//Check if the value has been set to your string and if it has set it to be the textField's text
if someStringVariable != nil {
textField.text = someStringVariable
}
}

Swift: prepareForSegue with two different segues

I have 2 UIButtons on a view.
Each of them are linked to 2 different views.
They have to pass different data depending which button you just tapped.
I know there is different way to segue but I want to use the prepareForSegue version for each (seems more clear for me to have the segue drawn on the storyboard and some code to explain what happened).
I tried this...
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if (segue != "historySegue") {
let controller = segue.destinationViewController as! ResultViewController
controller.match = self.match
} else {
let controller = segue.destinationViewController as! HistoryViewController
controller.history = self.history
}
}
#IBAction func showHistory(sender: UIButton) {
performSegueWithIdentifier("historySegue", sender: self)
}
#IBAction func match(sender: UIButton) {
performSegueWithIdentifier("matchSegue", sender: self)
}
But I got an error when I click the buttons
(lldb)
Take out your IBActions (making sure to delete them in the Connections Inspector via the right side bar in the Interface Builder as well as in your code). For the segues, just use the Interface Builder, make sure both segue's identifiers are correct, then try this prepareForSegue method:
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if segue.identifier == "matchSegue" {
let controller = segue.destinationViewController as! ResultViewController
controller.match = self.match
} else if segue.identifier == "historySegue" {
let controller = segue.destinationViewController as! HistoryViewController
controller.history = self.history
}
}
You could switch it...
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if let identifier = segue.identifier {
switch identifier {
case "matchSegue":
let controller = segue.destinationViewController as! ResultViewController
controller.match = self.match
case "historySegue":
let controller = segue.destinationViewController as! HistoryViewController
controller.history = self.history
}
}
}
You should compare the segue.identifier with the string not segue:
segue.identifier == "historySegue"
It won't fix your problem but it helps later.
I believe you have added an breakpoint and your app just stop at it. Remove the breakepoint and it will work.
prepareForSegue with two different segues
when you click on button uialert controller will show it will give you three options 1. physical, 2. online and 3. cancel.
#objc func twoSegues(sender : UIButton) {
let alert = UIAlertController(title: "Update Request", message: "Are you sure to update the record!", preferredStyle: .alert)
let yes = UIAlertAction(title: "Yes", style: .default, handler: { [weak self] (UIAlertAction) in
if(serviceType == "physical") {
DispatchQueue.main.async {
self?.performSegue(withIdentifier: "physical", sender: self?.myArray[id!].serviceID)
}
}
if(serviceType == "online") {
DispatchQueue.main.async {
self?.performSegue(withIdentifier: "online", sender: self?.myArray[id!].serviceID)
}
}
})
let no = UIAlertAction(title: "No", style: .default, handler: nil)
alert.addAction(yes)
alert.addAction(no)
self.present(alert, animated: true, completion: nil)
}
}
In order to navigate different segues in objective C you need to follow these actions.
Click on the actual segue on storyboard
Go to attribute inspector and rename the identifier of the segue
customize the code as following, here's an example:
-(void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
if([segue.identifier isEqualToString:#"segueNumberOne"]){
YourViewController *functionalityViewController = [segue destinationViewController];
functionalityViewController.someProperty = someValue;
NSLog(#"move to segue number 1");
}else if ([segue.identifier isEqualToString:#"segueNumberTwo"]){
NSLog(#"move to segue number 2");
}

Adding function to sidebar menu on Swift

So I just did a tutorial on adding a blurry sidebar menu. I replicated the code but I cant seem to find out how to call my other ViewControllers I made in storyboard mode.
I have created files and linked them to UIViewControllers. But when I try to call that ViewController with my sidebar menu I'm getting a black screen.
Here is the link of the files I used to follow along http://goo.gl/ULWxJh
And here is the link of the youtube video I followed along with http://www.youtube.com/watch?v=qaLiZgUK2T0
Not sure why! Any help would be greatly appreciated
class ViewController: UIViewController, SideBarDelegate {
var sideBar:SideBar = SideBar() // Side Bar
override func viewDidLoad() {
super.viewDidLoad()
// Side bar action and text
sideBar = SideBar(sourceView: self.view, menuItems: ["Home", "Business Directory", "Classifieds", "Featured News", "Jobs", "Restaurants", "Sports"])
sideBar.delegate = self
}
// Side Bar funcion
func sideBarDidSelectButtonAtIndex(index: Int) {
if index == 0{
let vc = ViewController()
self.presentViewController(vc, animated: true, completion: nil)
}else if index == 1{
let vc = businessDirectoryVC()
self.presentViewController(vc, animated: true, completion: nil)
}
}
}
Add a Storyboard ID (in this case "view") to the View Controller in your Main Storyboard and then add the following to the file from where you want to call the sidebar from:
func sideBarDidSelectButtonAtIndex(index: Int) {
if index == 0 {
let storyBoard:UIStoryboard = UIStoryboard(name: "Main", bundle:nil)
let showView = storyBoard.instantiateViewControllerWithIdentifier("view") as! ViewController
self.presentViewController(showUebersicht, animated:true, completion:nil)
}
}
Value "0" stands for the first item in the sidebar. Change the value for another value of the array where the items of the sidebar are stored.

Resources