How to show segue from bottom of the screen - ios

I created a segue between two controllers(A, B). In controller A, I am using "performSegueWithIdentifier" method to show controller B's view. However, I want to add an animation on presenting the B. I want it to show/hide from the bottom of the screen. How should I do this?

I achieved this using Present As Popover when choosing the kind of segue in Attributes Inspector. Make sure you point your anchor to the view controller you are segueing from, this answer was pretty helpful.
Make sure you give it an identifier (using this identifier below) and use the typical perform segue code whenever you wish to perform the segue:
dispatch_async(dispatch_get_main_queue()) {
[unowned self] in
self.performSegueWithIdentifier("Identifier", sender: self)
}
Make sure you replace "Identifier" string with a string of your own segue identifier.

Related

"no segue with identifier" when using 'Unwind Segue' with a storyboard reference

I've followed the instructions here and here which suggest that I should be able to create an unwind/edit segue even when using a storyboard reference.
The flow is quite simple:
PhotoDetailScene has a storyboard reference to EditHistoryScene and a tap gesture to trigger the segue, then I have a close button on EditHistoryScene that unwinds back to PhotoDetailScene. The present works fine (the custom 'show' segue opens the EditHistoryScene), and if I use a dismiss() call it dismisses fine. But unwinding with the segue identifier always fails with:
EditHistoryScene has no segue with identifier 'UnwindEditHistorySegue'
In my EditHistoryScene close button action, I have:
func closeButtonPressed(_ sender: Any)
performSegue(withIdentifier: "UnwindEditHistorySegue", sender: self)
}
And in my PhotoDetailScene, I have added:
#IBAction func unwindToPhotoDetailScene(_ unwindSegue: UIStoryboardSegue) {
print("It works!")
}
And here's how I've set it up in IB, with the unwindToPhotoDetailScene() method connected to the storyboard reference (since that's the only way IB would let me ctrl+link the outlet):
Presenting segue:
Unwind segue properties (and segue name)
Storyboard reference correctly set for destination storyboard:
Storyboard reference's exit point connected back to PhotoDetailScene:
EditHistoryScene storyboard instance appears to not be connected to the #IBOutlet?
My best guess is that it's failing because this is a storyboard reference, and the unwind segue is defined on the reference, not the actual storyboard instance. But I can't figure out how to attach the EditHistoryScene's exit point to the PhotoDetailScene directly.
You don't need to create any segues to the reference itself.
Once your second storyboard contains a reference to the first storyboard, any unwind functions defined in the first storyboard are available.
You create exit segues by dragging from the exit trigger to the exit icon in the view controller scene.
If you want to trigger the unwind from your "close" button, simply ctrl-drag from the close button to the "exit" icon at the top of its view controller and you will see unwindToPhotoDetailScene as an option.
You only need to give the segue an identifier if you want to trigger it programatically.
For example, you might want an action handler function on the close button that checks to see if there are unsaved changes. If there are, prompt the user to confirm that they will lose their changes (or to save or whatever). Once they are happy to proceed you can the invoke the unwind.
To set this up, ctrl-drag from the view controller object to its own exit icon. Create the unwind segue and give it an identifier.

Creating multiple segues from one UIButton to the same view controller or another

i'm fairly new to swift, so please bear with me.
right now my problem can be broken down to this:
I have one Test View Controller that can display my 'Test' object by showing the description and the title. I also have an array of Test objects. In the top right hand corner, there is a 'skip this test' button, and if the user clicks on it, the viewcontroller will segue to itself, but change the Test object that is being displayed, e.g. its just basically looping through an array of Tests. I have changed the prepare for segue methods accordingly to push the data through the view controllers.
However, I want to be able to move to a completely different ViewController (lets just call it FinalViewController) if I have reached the last Test in my Test array.
Now this is the part that I can't fix.
I would like to create a segue directly from the 'skip test' button, only that it segues to a different view controller, depending on a certain condition. However, as i tried creating a segue in IB by right clicking on the Button and pulling it to the FinalViewController, it erased my previous segue I had for that button.
Does anybody know if there is a fix for this problem? thank you!!!!
However, as i tried creating a segue in IB by right clicking on the
Button and pulling it to the FinalViewController, it erased my
previous segue I had for that button
Actually, you don't want to do that, instead, you should drag from the controller itself, not from the button because if your segue has been created based on a button, tapping on it should always perform it and this is NOT what you want.
After creating a segue from the ViewController, you can -programmatically- call performSegue method and handle what data should be passed to the next viewController by implementing prepareForSegue method.
For more information, check my answer to know how to create multiple segues with identifiers and work with them.
EDIT:
If you want to push to the same current ViewController, performSegue method would not be the optimal solution. You should instead push/present to same ViewController it self:
class ViewController: UIViewController {
var myString: String?
override func viewDidLoad() {
super.viewDidLoad()
// here we go
let storyboard = UIStoryboard(name: "Main", bundle: nil)
let sameViewController = storyboard.instantiateViewControllerWithIdentifier("ViewControllerStoryboardID") as! ViewController
sameViewController.myString = "the value of the new myString"
navigationController?.pushViewController(sameViewController, animated: true)
print(myString)
}
}
Probably, you don't want to implement it in viewDidLoad, it's just for demonstration purpose.
Make sure that the ViewController has a storyboard ID (in code snippet, I assume it is "ViewControllerStoryboardID"):

Returns to orginal view after segue

I have a view controller, after a button is pressed I want it to unwind to the original table view controller and then let it segue into another view controller.
I don't segue directly to the new view controller because I want that when the back button gets pressed it returns to the original table view controller.
But when I do this it loads the view controller where it's supposed to end, but directly after that it directly returns to the original table view controller
This is my setup in storyboard:
http://imgur.com/dcvvxi5
And this is the code I use to make it happen.
I call this code in the view controller where the button gets pressed:
self.performSegueWithIdentifier("unwindChooseHome", sender: nil)
And this code inside the original table view controller:
#IBAction func unwindChooseHome(segue: UIStoryboardSegue) {
self.performSegueWithIdentifier("destination", sender: nil)
}
Hopefully you understand my question I am not native. I don't really know what I am doing wrong maybe there's a totally different way to make this happen.
Thanks in advance :)
I imagine that the problem is that you're triggering the "destination" segue prior to the completion of the unwind segue.
Instead of triggering the "destination" segue immediately inside of the unwind action method, try setting a flag on the original view controller that you can then check in viewDidAppear: and trigger the segue at that point.

Swift: Custom class array in table view - editing the values: accessory segue or other?

I have a custom class Medication with variables name and directions. I have this in an array presenting itself in a tableview showing Medication.name and Medication.directions.
I'd like the user to be able to click either on the row or on the accessory button (Detail?) to edit the value in the selected row.
My ideal situation would be a menu that dropped down from the bottom of the selected row with editable fields that would update the row in the array and reload the tableview.
Is there a way to accomplish this or something similar? I was playing around with hidden view fields and having them show when the row is selected, but I'm not sure if I can anchor one to the bottom of the selected row? Or I could build a custom cell that has the editable fields in each cell, hidden, with a fixed height to the cell that changes upon clicking it to show the extra fields.
Likewise, if the best option is to use the accessory view, is Detail the most appropriate one? I can't seem to right click and drag a segue for this. Or would I just use this below?
optional func tableView(_ tableView: UITableView,
accessoryButtonTappedForRowWithIndexPath indexPath: NSIndexPath)
If I segue this to another view controller, I'll need to use delegates obviously to change the array from the tableview so I'm hoping to find a simpler solution.
Thanks! Appreciate any tips for this newbie
Here's where I'm stuck with the segue:
let vc = segue.destinationViewController as! MedDetailViewController
vc.delegate = self
let MedRow = self.tableView.indexPathForSelectedRow()!
let passMed = myMedsList[MedRow] //this row doesn't work
vc.detailMed = passMed
A segue is not only the simplest way to accomplish this, you can also take advantage of an unwind segue to automatically return your edited values.
No delegation needed. No custom code to add hidden views to your cell.
If you only have one segue, add it to the row, not the accessory. Users tend to expect that tapping on the row does something. If it didn't do anything, most users wouldn't then try tapping on the accessory.
Tapping on the accessory is meant as a secondary action that does something different from tapping on the row.
I would setup the show segue right in Storyboard. Less code to write, less code to maintain. Let Storyboard do the work for you.
Update:
Here's Apple's tech note about Using Unwind Segues, along with their Swift example of how the destination (presenting) view controller accesses data from the source (presented) view controller.
#IBAction func unwindToMainMenu(sender: UIStoryboardSegue)
{
let sourceViewController = sender.sourceViewController as! MedDetailViewController
// Update the medsList array with the new detailMed
let medRow = self.tableView.indexPathForSelectedRow().row
medsList[medRow] = sourceViewController.detailMed
}
Update 2:
You want to update the detail view controller's detailMed property before you unwind the segue, using the prepareForSegue: method.
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if segue.identifier == "unwindToMedications"
{
// Update the detailMed if the user has edited it
self.detailMed = ... // the edited medication you're returning
}
}
Update 3:
The back button (or swiping back) simply pops the pushed view controller off the stack, but there's no segue that's being called. You need to explicitly hook up a segue from a Done button that will unwind for you and update the meds list.
The reason why you explicitly unwind is to distinguish between whether the user wants to commit or cancel any change. (Did they make a change, but they want to ignore it, so they pressed Back?)
You have two options, which both will work, and it's up to you how you want to present the editable details. (I prefer push to show details, and modal for editing forms, but either way works).
Push the detail view controller. Have a Done button. The user can use the Back button to cancel, or the Done button to accept any changed med details.
Present a modal view controller with Cancel and Done buttons. Again, the user can cancel (return without changes), or tap Done to (return and) accept changes.
For either presentation, you hook up an unwind segue to the Done button. What this will do is call the Meds list view controller unwind action. In that unwind code, you get the med details and update the meds list, as we previously discussed.
A mention about Core Data:
There's an alternative approach which isn't simpler to learn than segues, but it's a great fit. (Something to keep in mind, if not for this app, then for the next one.)
Core Data and NSFetchedResultsController. You save the edited medication, and NSFetchedResultsControllerDelegate updates the list of medications for you.
Some might say it's overkill, but since I started using NSFetchedResultsController, I wish I had learned it sooner.

iOS UICollectionView navigation

I'm trying to figure out how to navigate around my app. But i'm a little lost.
I have a UIViewController that loads some data, then displays the data in a CollectionView. Then I have another UIViewController for the detailed view. I then trigger a segue to go to it, I pass the data etc.
self.performSegueWithIdentifier("detailViewSeque", sender: nil)
But the part i'm lost on is getting back to my main view, if I just trigger another segue then it loads all the data / view again. The data has already been loaded once, I really don't want to keep loading it.
I feel like I'm doing things wrong, that theres some super obvious way to handle this scenario.
Could someone point me in the right direction?
This is good situation to use an unwind segue (for more information: What are Unwind segues for and how do you use them?). Here's how to setup one up:
Firstly, create an #IBAction in the view controller you want to segue to, that takes a UIStoryboardSegue as its only argument. For example:
#IBAction func unwindToHere(segue: UIStoryboardSegue) {
// If you need you have access to the previous view controller
// through the segue object.
}
Secondly, you need to create the unwind segue in IB. To do this ctrl-drag from the view controller you want to segue from, to Exit and select the unwindToHere method:
Thirdly, you need to give your segue and identifier. To do this select your segue (see below - your segue will not be visible like normal segues); then use the Attribute Editor to give your segue an identifier.
Now you can use your segue. On the view controller you want to segue from, call:
self.performSegueWithIdentifier("YourID", sender: self)
To rephrase your needs "I have data that I need to keep around somewhere that isn't associated with a view controller".
You have a few options here. Your goal is basically to store it somewhere that isn't going to go out of memory.
The AppDelegate gets used for this purpose a lot but Singleton variable works as well.
I would personally create a singleton, say CatPictureRetriever with
private let _CatPictureRetriever SharedInstance = CatPictureRetriever()
class CatPictureRetriever {
static let sharedInstance = CatPictureRetriever()
var catPictures : NSArray?;
func gimmeCatPictures -> NSArray? {
return catPictures
}
}
Now you can get your pictures though your CatPictureRetriever anywhere
var pictures = CatPictureRetriever.sharedInstance.gimmeCatPictures()

Resources