How to send data back by popViewControllerAnimated for Swift?
You can pass data back using delegate
- Create
protocol
inChildViewController
- Create
delegate
variable inChildViewController
- Extend
ChildViewController
protocol inMainViewController
- Give reference to
ChildViewController
ofMainViewController
whennavigate
- Define
delegate
Method inMainViewController
- Then you can call
delegate
method fromChildViewController
Example
In ChildViewController: Write code below...
protocol ChildViewControllerDelegate
{
func childViewControllerResponse(parameter)
}
class ChildViewController:UIViewController
{
var delegate: ChildViewControllerDelegate?
....
}
In MainViewController
// extend `delegate`
class MainViewController:UIViewController,ChildViewControllerDelegate
{
// Define Delegate Method
func childViewControllerResponse(parameter)
{
.... // self.parameter = parameter
}
}
There are two options:
A) with Segue
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?)
{
let goNext = segue.destinationViewController as ChildViewController
goNext.delegate = self
}
B) without Segue
let goNext = storyboard?.instantiateViewControllerWithIdentifier("childView") as ChildViewController
goNext.delegate = self
self.navigationController?.pushViewController(goNext, animated: true)
Method Call
self.delegate?.childViewControllerResponse(parameter)
Swift popViewController Send Data
You seem to be trying to pass data from SelectTag
to MyPage
.
One way to do this is to use the delegate pattern.
Create a SelectTagDelegate
:
protocol SelectTagDelegate : class {
func didSelectTag(tags: [Int])
}
Add this property in SelectTag
:
weak var delegate: SelectTagDelegate?
And then change endSelectTag
to:
@IBAction func endSelectTag(_ sender: Any) {
delegate?.didSelectTag(tags: selectedTag)
self.navigationController?.popViewController(animated: true)
}
Make MyPage
conform to SelectTagDelegate
by implementing didSelectTag
:
extension MyPage: SelectTagDelegate {
func didSelectTag(tags: [Int]) {
seleteTag = tags
}
}
Now, when you are presenting SelectTag
, set self
as the delegate.
let selectTag = // get VC from storyboard or use segue.destination depending on your situation
selectTag.delegate = self
// present the VC
Swift – Using popViewController and passing data to the ViewController you're returning to
So I figured it out, based mostly from this post – http://makeapppie.com/2014/09/15/swift-swift-programmatic-navigation-view-controllers-in-swift/
In SecondViewController
, above the class declaration, add this code:
protocol SecondVCDelegate {
func didFinishSecondVC(controller: SecondViewController)
}
Then inside of SecondViewContoller
add a class variable:
var delegate: MeditationVCDelegate! = nil
Then inside of your function that your button targets, add this:
self.navigationController?.popViewControllerAnimated(true)
delegate.didFinishSecondVC(self)
What we're doing here is doing the pop in SecondViewController
, and not passing any data, but since we've defined a protocol, we're going to use that in ViewController
to handle the data.
So next, in ViewController
, add the protocol you defined in SecondViewController
to the list of classes ViewController
inherits from:
class ViewController: UIViewController, SecondVCDelegate { ... your code... }
You'll need to add the function we defined in the new protocol in order to make the compiler happy. Inside of ViewController
's class, add this:
func didFinishSecondVC(controller: SecondViewController) {
self.myBoolVar = true
controller.navigationController?.popViewControllerAnimated(true)
}
In SecondViewController
where we're calling didFinishSecondVC
, we're calling this method inside of the ViewController
class, the controller we're popping to. It's similar to if we wrote this code inside of SecondViewController
but we've written it inside of ViewController
and we're using a delegate to manage the messaging between the two.
Finally, in ViewController
, in the function we're targeting to push to SecondViewController
, add this code:
let secondVC = secondViewController()
secondVC.delegate = self
self.navigationController?.pushViewController(secondVC, animated: true)
That's it! You should be all set to pass code between two view controllers without using storyboards!
how to pass data after pop view controller in swift
In the ScanView
you are creating the new instance of UploadMain
, that is not available in window hierarchy, So that data is not available to the UploadMain
. To solve your problem you need to create one protocol
and pass the delegate of that protocol to ScanView
. So create one protocol
like this.
protocol IsbnDelegate {
func passData(isbnStr: String)
}
Now inherit this protocol in UploadMain
and override its method passData
in the UploadMain
like below
class UploadMain: UIViewController,UITextFieldDelegate,IsbnDelegate {
//your code
//Add this method
func passData(isbnStr: String) {
self.ISBN.text = isbnStr
}
//Also override prepareForSegue like this
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
let destVC = segue.destinationViewController as! ScanView
destVC.delegate = self
}
}
After that create one delegate
object in ScanView
, Change your code of ScanView
like this
import UIKit
import AVFoundation
import Foundation
class ScanView : UIViewController, AVCaptureMetadataOutputObjectsDelegate {
let session : AVCaptureSession = AVCaptureSession()
var previewLayer : AVCaptureVideoPreviewLayer!
var detectionString : String!
let apiKey : String = "---------dddddd"
var delegate: IsbnDelegate?
override func viewDidLoad() {
super.viewDidLoad()
// For the sake of discussion this is the camera
let device = AVCaptureDevice.defaultDeviceWithMediaType(AVMediaTypeVideo)
// Create a nilable NSError to hand off to the next method.
// Make sure to use the "var" keyword and not "let"
var error : NSError? = nil
var input: AVCaptureDeviceInput = AVCaptureDeviceInput()
do {
input = try AVCaptureDeviceInput(device: device) as AVCaptureDeviceInput
} catch let myJSONError {
print(myJSONError)
}
// If our input is not nil then add it to the session, otherwise we're kind of done!
if input != AVCaptureDeviceInput() {
session.addInput(input)
}
else {
// This is fine for a demo, do something real with this in your app. :)
print(error)
}
let output = AVCaptureMetadataOutput()
output.setMetadataObjectsDelegate(self, queue: dispatch_get_main_queue())
session.addOutput(output)
output.metadataObjectTypes = output.availableMetadataObjectTypes
previewLayer = AVCaptureVideoPreviewLayer(session: session)
previewLayer.frame = self.view.bounds
previewLayer.videoGravity = AVLayerVideoGravityResizeAspectFill
self.view.layer.addSublayer(previewLayer)
// Start the scanner. You'll have to end it yourself later.
session.startRunning()
}
// This is called when we find a known barcode type with the camera.
func captureOutput(captureOutput: AVCaptureOutput!, didOutputMetadataObjects metadataObjects: [AnyObject]!, fromConnection connection: AVCaptureConnection!) {
var highlightViewRect = CGRectZero
var barCodeObject : AVMetadataObject!
let barCodeTypes = [AVMetadataObjectTypeEAN13Code, AVMetadataObjectTypeEAN8Code]
// The scanner is capable of capturing multiple 2-dimensional barcodes in one scan.
for metadata in metadataObjects {
for barcodeType in barCodeTypes {
if metadata.type == barcodeType {
barCodeObject = self.previewLayer.transformedMetadataObjectForMetadataObject(metadata as! AVMetadataMachineReadableCodeObject)
highlightViewRect = barCodeObject.bounds
detectionString = (metadata as! AVMetadataMachineReadableCodeObject).stringValue
self.session.stopRunning()
self.alert(detectionString)
// Daum Book API 호출
let apiURI = NSURL(string: "https://apis.daum.net/search/book?apikey=\(apiKey)&q=\(detectionString)&searchType=isbn&output=json")
let apidata : NSData? = NSData(contentsOfURL: apiURI!)
NSLog("API Result = %@", NSString(data: apidata!, encoding: NSUTF8StringEncoding)!)
//Here We are passing the data of your ScanView to UploadMain
self.delegate.passData(self.detectionString!)
break
}
}
}
print(detectionString)
self.navigationController?.popViewControllerAnimated(true)
}
func alert(Code: String){
let actionSheet:UIAlertController = UIAlertController(title: "Barcode", message: "\(Code)", preferredStyle: UIAlertControllerStyle.Alert)
// for alert add .Alert instead of .Action Sheet
// start copy
let firstAlertAction:UIAlertAction = UIAlertAction(title: "OK", style: UIAlertActionStyle.Default, handler:
{
(alertAction:UIAlertAction!) in
// action when pressed
self.session.startRunning()
})
actionSheet.addAction(firstAlertAction)
}
}
For more detail about protcol
follow this link
1) Apple Documentation
2) Tutorial 1
3) Tutorial 2
Hope this will help you.
it possible to Pass Data with popViewControllerAnimated?
The best way to do it is by using a delegate.
//SecVCDelegate.h
#import <Foundation/Foundation.h>
@protocol SecVSDelegate <NSObject>
@optional
- (void)secVCDidDismisWithData:(NSObject*)data;
@end
//SecVC.h
#import <UIKit/UIKit.h>
#import "SecVSDelegate.h"
@interface SecVC : UIViewController
/** Returns the delegate */
@property (nonatomic, assign) id<SecVSDelegate> delegate;
@end
//SecVC.M
...
- (void) dealloc
{
...
delegate = nil
...
}
When ever you popViewControllerAnimated, right after it (or before it) you do this
if(_delegate && [_delegate respondsToSelector:@selector(secVCDidDismisWithData:)])
{
[_delegate secVCDidDismisWithData:myDataObject];
}
And in the MainVC you must be certain that you implement the delegate function
//MainVC.m
- (void)secVCDidDismisWithData
{
//do whatever you want with the data
}
To avoid any warnings you must tell that the MainVC class implements the delegate like this:
//MainVC.h
#import "SecVCDelegate.h"
...
@interface MainVC : UIViewController <SecVCDelegate>
...
secVCInstance.delegate = self;
[self.navigationController pushViewController:secVCInstance];
...
Pass data back to previous viewcontroller
You can use a delegate. So in your ViewController B you need to create a protocol that sends data back to your ViewController A. Your ViewController A would become a delegate of ViewController B.
If you are new to objective C, please look at What is Delegate.
Create protocol in ViewControllerB.h :
#import <UIKit/UIKit.h>
@protocol senddataProtocol <NSObject>
-(void)sendDataToA:(NSArray *)array; //I am thinking my data is NSArray, you can use another object for store your information.
@end
@interface ViewControllerB : UIViewController
@property(nonatomic,assign)id delegate;
ViewControllerB.m
@synthesize delegate;
-(void)viewWillDisappear:(BOOL)animated
{
[delegate sendDataToA:yourdata];
}
in your ViewControllerA : when you go to ViewControllerB
ViewControllerA *acontollerobject=[[ViewControllerA alloc] initWithNibName:@"ViewControllerA" bundle:nil];
acontollerobject.delegate=self; // protocol listener
[self.navigationController pushViewController:acontollerobject animated:YES];
and define your function:
-(void)sendDataToA:(NSArray *)array
{
// data will come here inside of ViewControllerA
}
Edited :
You can See this example : How you can Pass data back to previous viewcontroller: Tutorial link
Pass data back to uiviewcontroller on pop (NavigationController.PopViewController)
NavigationController
keeps track of all the ViewControllers as an array: NavigationController.ViewControllers
You can get an existing instance of the ViewController
Type from this array via following code:
(You may write this method in BaseViewController
if you have it.)
public T InstanceFromNavigationStack<T> () where T : UIViewController
{
return (T)NavigationController.ViewControllers.FirstOrDefault(v => v is T);
}
Then use it like :
var myVCInstance = InstanceFromNavigationStack<MyTargetViewController>();
if(myVCInstance != null)
{
//Assign a value like
myVCInstance.MyVariable = "MyValue";
//Or call a method like
myVCInstance.MethodToReloadView("MyValue")
}
//Go Back Navigation Code
//Then here write your navigation logic to go back.
This not only helps passing data in Previous ViewController, but Any ViewController in the stack. Simply pass the Type of it to get an Instance from Stack.
NOTE: This should work if your Navigation stack doesn't have multiple instance of the same ViewController
Type.
Swift / how to call delegate with popViewController
You can set the delegate of My3rdVC
in the prepareForSegue
method of My2ndVC
.
class My2ndVC: UIViewController, PassClubDelegate {
...
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
super.prepareForSegue(segue, sender: sender)
switch segue.destinationController {
case let controller as My3rdVC:
controller.passClubDelegate = self
}
}
}
This is assuming you have created a segue in your storyboard that pushes My3rdVC
from My2ndVC
onto the navigation controller stack, which I'm assuming you have. So just try simply pasting this prepareForSegue
method into My2ndVC
and see if it works.
UPDATE
let vc = stb.instantiateViewControllerWithIdentifier("My3rdVC") as! My3rdVC
vc.passClubDelegate = self
navigationController?.pushViewController(vc, animated: true)
Programmatically go back to previous ViewController in Swift
Swift 3:
If you want to go back to the previous view controller
_ = navigationController?.popViewController(animated: true)
If you want to go back to the root view controller
_ = navigationController?.popToRootViewController(animated: true)
If you are not using a navigation controller then pls use the below code.
self.dismiss(animated: true, completion: nil)
animation value you can set according to your requirement.
Related Topics
Uitableview - Scroll to the Top
How to Update a Localized Storyboard's Strings
Difference Between Dispatchqueue.Main.Async and Dispatchqueue.Main.Sync
How to Style Uitextview to Like Rounded Rect Text Field
iPhone "Slide to Unlock" Animation
Saving Email/Password to Keychain in iOS
What Does "@Private" Mean in Objective-C
Building for iOS Simulator, But the Linked Framework '****.Framework' Was Built for iOS
Ibeacon Notification When the App Is Not Running
How to Store an Image in Core Data
Pod Install -Bash: Pod: Command Not Found
iOS Enterprise Distribution Through Ota
Passing Data to Apple Watch App
How to Get Download Progress in Afnetworking 2.0
Gradient Polyline with Mapkit iOS
Example for Login Screen Modally Based on Storyboard
Trigger Local Notifications Automatically Daily on Dynamic Time Given in Arrays Objective C iOS