performSegue to same ViewController from delegate method - swift

I'm trying to perform a segue from ViewController A to ViewController A (same VC). I can do that when I ctrl+drag from a button to the VC and set the identifier ("sameVC" in my case).
When the button is tapped, the segue works as expected. The problem is, I need to call
self.performSegue(withIdentifier: "sameVC", sender: self)
from a delegate. So when the button is tapped, I need to call a function, that has a delegate, like this:
class ViewControllerA: ViewController, MyDelegate {
var mC = MyClass()
override func viewDidLoad() {
mC.delegate = self
}
#IBAction func buttonTapped(_ sender: UIButton) {
mC.myfunc()
}
func success {
// Trying to call delegate
self.performSegue(withIdentifies: "sameVC", sender: self)
}
}
protocol MyDelegate {
func success()
}
class MyClass {
var delegate: MyDelegate?
func myfunc() {
// ...
self.delegate.success()
}
}
When the delegate comes back to ViewControllerA in "success"-function, I want to perform the segue, but the View isn't present anymore, because the segue was called implicit with "buttonTapped"-function.
When the segue isn't going to the same VC, I would just ctrl+drag from ViewControllerA to ViewControllerB, but this isn't possible with only one ViewController (or I don't know how to do this).
Is there any way I can achieve this?

Instead of ctrl+dragging from button, ctrl+drag from ViewController itself, then it will wait for you to call performSegue
And for going from you have more than one viewcontrollers you may want to navigate to, you can assign an Identifier to your viewControllers in your storyboard and use storyboard.instantiateViewControllerWithIdentifier method to instantiate your desired ViewController and present it to the user, e.g. push it on top of current viewcontroller.

Related

Reload main view after modal dismiss

In my Xcode-App, a modal can be opened from every view. Every 'base' view is having a different purpose, some are showing a table, some are doing not. How can I achieve to reload the 'base' view whenever the modal is dismissed?
It seems to be especially tricky as the views have such different structures and purposes. I tried viewWillAppear, viewDidAppear and viewDidLoad, but none of them seem to do the trick.
You can setup a delegate pattern so that your modal view can notify when it will or did disappear.
First you need to create a protocol for your delegate:
protocol ModalViewControllerDelegate: class {
func modalControllerWillDisapear(_ modal: ModalViewController)
}
Then your modal should have a delegate property (that will in the end be the presenting controller) and trigger the modalControllerWillDisapear method when needed:
final class ModalViewController: UIViewController {
weak var delegate: ModalViewControllerDelegate?
override func viewWillDisappear(_ animated: Bool) {
super.viewWillDisappear(animated)
delegate?.modalControllerWillDisapear(self)
}
}
And all view controller that will present your modal controller must conform to that protocol and assign itself as a delegate of the modal when presenting:
final class SomeViewController: UIViewController {
private func presentModalController() {
let modal = ModalViewController()
modal.delegate = self
self.present(modal, animated: true)
}
}
extension SomeViewController: ModalViewControllerDelegate {
func modalControllerWillDisapear(_ modal: ModalViewController) {
// This is called when your modal will disappear. You can reload your data.
print("reload")
}
}
Note: If you are using segues to present your modal, you can assign the delegate property in the prepare(for:sender:) method instead of in a custom method.
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
switch (segue.identifier, segue.destination) {
// Check that the segue identifer matches and destination controller is a ModalViewController
case ("showModalSegue", let destination as ModalViewController):
destination.delegate = self
case _:
break
}
}

Run method when viewcontroller is accessed from another vc being dismissed

Let's say I have my initial vc called VC1, then I have a second one called VC2. VC1 has a segue to VC2, on VC2 there is a button that will dismiss VC2 and then show VC1. Once VC1 loads I want to run a method but I can't do that in view did load so where can I do it?
[VC1] -> [VC2]
You can also try Unwind Segue for dismissing the VC2 and call methods in VC1. It is very easy and requires less coding.
In your VC1 add below method:
#IBAction func unwindToVC1(segue:UIStoryboardSegue){
print("Hello")
}
In storyboard right click on Exit icon of VC1 and and connect a segue to VC2:
Then in storyboard in VC2 select the unwindSegue and name it :
now in the method where you are dismissing the VC2 just add:
performSegue(withIdentifier: "dismissSegue", sender: self)
you can also pass data from VC2 to VC1.
You can use a delegate method to achieve this. In the method you call to dismiss VC2 call the delegate. You can implement this delegate in VC1.
In VC1:
Delegate of VC2 and in VC1 Controller in Class or extension
add the delegate method into VC1 that would called after dismiss the VC2
In VC2:
Add the protocol of VC1 and make the object of Protocol delegate then its segue exit it goto VC1 Delegate method.
Example:
VC1:
extension VC1, myCustomVC2Delegate {
func didCloseDelegate() {
// Your function or method Called here
}
}
VC2:
protocol myCustomVC2Delegate {
func didCloseDelegate()
}
import UIKit
class VC2: UIViewController {
var delegate: myCustomVC2Delegate?
#IBAction func onTapGotoVC1(_ sender: AnyObject) {
self.performSegue(withIdentifier: "gotoVC1", sender: self)
}
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == "gotoVC1" {
if self.delegate != nil {
self.delegate?.didCloseDelegate()
}
}
}

nothing happens on trying to dismiss popover viewcontroller Swift

I have a viewcontroller that is presented as popover when the user clicks on an ImageView.
The problem is, I added a button to dismiss it but when I tap on it nothing happens.
The code I have is:
#IBAction func onCloseTapped(_ sender: Any) {
presentedViewController?.dismiss(animated: true, completion: nil)
}
I've also tried dismiss(animated: true, completion: nil) and other methods, but still nothing.
Can anyone tell me what I am doing wrong?
Edit: Posting a screenshot:
Edit 2: I'm presenting it from the storyboard. I've added a gesture recognizer on the image, then added segue from the storyboard that says present as popover, then anchor to the image.
it won't work because when you show as popover, the viewController doesn't have the navigationController. You have to create a delegate method and use the dismiss function on the viewController that make the call to the popover.
Here an exemple:
make the popover delegate, in the popover viewController:
protocol PopoverViewControllerDelegate: NSObjectProtocol {
func dismiss()
}
then you create a delegate variable and call when the button is tapped:
var delegate: PopoverViewControllerDelegate?
#IBAction func onCloseTapped(_ sender: Any) {
delegate?.dismiss()
}
Now in the viewController that call the popover you override the prepare for segue method to set the popover delegate:
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == "popover" {
if let vc = segue.destination as? PopoverViewController {
vc.delegate = self
}
}
}
Now you just need to use the delegate to dismiss your popover viewController:
extension ViewController: PopoverViewControllerDelegate {
func dismiss() {
navigationController?.dismiss(animated: true, completion: nil)
}
}
Don't forget to put the identifier for you segue, the identifier that we use is this = "popover"
Hope that help you.

Stop animation of first view controller when second is started swift programming

How to stop animation of first view controller when second is started in swift programming. I have created a function which stops animation in first view controller. I want it to be called in second view controller.
In first View Controller
func stopAni(){
self.resultView.stopAnimating()
ButtonAudioPlayer.stop()
ButtonAudioPlayer1.stop()
ButtonAudioPlayer2.stop()
ButtonAudioPlayer3.stop()
ButtonAudioPlayer4.stop()
ButtonAudioPlayer5.stop()
ButtonAudioPlayer6.stop()
Not sure how to call this function in second view controller.
You can create a delegate something like:
protocol StopAnimationDelegate{
func stopAnimations()
}
Then, on your first view controller you're going to adopt this protocol:
class FirstViewController : UIViewController, StopAnimationDelegate{
//..... here code
func stopAnimations(){
//Stop your animations or call your method stopAni here.
}
//.... here more code
#IBAction func openSecondViewController(sender:UIButton){
self.performSegueWithIdentifier("segue_first_second",sender:nil)
}
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if segue.identifier == "segue_first_second"{
let secondViewController = segue.destinationViewController as! SecondViewController
secondViewController.delegate = self
}
}
}
On your second view controller, you can make something like:
class SecondViewController: UIViewController{
var delegate:StopAnimationDelegate?
#override func viewDidLoad(){
delegate?.stopAnimations()
}
}
Note: That's a way of how you can accomplish that, but all depends on what you need to do, for example you can simply stop the animations when you perform the segue (but again, that depends on what you want to do).
Another option, is using NSNotificationCenter to post a notification to Stop the animation, something like:
In First View Controller:
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
NSNotificationCenter.defaultCenter().addObserver(self, selector: "stopAnim", name: "kStopAnimations", object: nil)
}
//...Your stopAnim method
//... More Code
}
class SecondViewController : UIViewController{
override func viewDidLoad() {
NSNotificationCenter.defaultCenter().postNotificationName("kStopAnimations", object: nil)
}
}

I segue from two viewControllers to one viewController. How to unwind segue to the caller?

Screenshot above is 2 segue; from (view1 or view2) to view3
When creating the unwind segue, how do I get it to call the right #IBAction method?
// code in view1.swift
#IBAction func backview1(segue: UIStoryboardSegue) {
}
// code in view2.swift
#IBAction func backview2(segue: UIStoryboardSegue) {
}
Should I add code in view3.swift?
How do I code the back segue method in view3.swift in order to go back to origin view?
To create a segue you can do it by CTRL clicking on an UI element, for instance, a UIButton to the destination UIViewController:
Then on both of your source UIViewController that you want to go back to from and unwind segue you need to implement the following method:
#IBAction func unwindSegue(segue: UIStoryboardSegue) { }
After doing this you can again CTRL drag to perform an unwind segue:
If you name the function you are returning to the same in both viewControllers, then you will be returned to the one that called VC3.
For example, put this in both VC1 and VC2:
#IBAction func backFromVC3(segue: UIStoryboardSegue) {
}
Then, when you create your unwind segue, just choose backFromVC3 from the pop-up.