ios 将数据传回上一个视图控制器

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/19343519/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-31 02:19:15  来源:igfitidea点击:

Pass data back to previous viewcontroller

iphoneiosobjective-cuiviewcontroller

提问by Anthony

I am trying to pass data BACK TO previous viewController.

我正在尝试将数据传递回以前的 viewController。

Does anyone know how to pass data back from ViewController B to ViewController A? So I want a string to go 'from' BIDAddTypeOfDealViewController to BIDDCCreateViewController. A user edits viewController B and I want that edited data back in ViewController A where I then use it.

有谁知道如何将数据从 ViewController B 传回 ViewController A?所以我想要一个字符串从 BIDAddTypeOfDealViewController 到 BIDDCCreateViewController。用户编辑了 viewController B,我希望将编辑过的数据放回 ViewController A 中,然后在那里使用它。

I am using the 'passing data back' section of this answer. How mine differs: Point 3 and 6 just mentions when views are popped so I have put that code in viewWillDisappear. I think that is correct? Also on Point 6 I did not initialise with nib as that is old. I'm using storyboards. And I did not add that last line as I do not believe I would have to push it. Pressing a button on my storyboard already takes me forward.

我正在使用此答案的“回传数据”部分。我的不同之处:第 3 点和第 6 点只是提到了何时弹出视图,因此我将该代码放在 viewWillDisappear 中。我认为这是正确的?同样在第 6 点,我没有用笔尖初始化,因为那是旧的。我正在使用故事板。我没有添加最后一行,因为我不相信我必须推动它。按我的故事板上的一个按钮已经让我前进了。

I think the problem may arise in BIDDCCreateViewController, I have the method but I cannot run it. To run a method it should go [self method]. I am unable to do that. Well that is just what I am guessing.

我认为问题可能出现在 BIDDCCreateViewController 中,我有方法但我无法运行它。要运行一个方法,它应该是 [self method]。我无法做到这一点。嗯,这正是我的猜测。

It compiles and runs fine just nothing is logged, so I don't know if it works.

它编译并运行良好,只是没有记录任何内容,所以我不知道它是否有效。

UPDATE: I am unable to get the 'sendDataToA' method to execute.

更新:我无法执行“sendDataToA”方法。

#import <UIKit/UIKit.h>
#import "BIDAddTypeOfDealViewController.h"

 @interface BIDDCCreateViewController : UIViewController
 @property (strong, nonatomic) NSString *placeId;
- (IBAction)gotoBViewController:(id)sender;
@end


#import "BIDDCCreateViewController.h"
#import "BIDAddTypeOfDealViewController.h"

@implementation BIDDCCreateViewController

- (void)viewDidLoad
{
    [super viewDidLoad];
    // Do any additional setup after loading the view.
    NSLog(@"SUCCESSFULLY PASSED PLACE ID: %@", self.placeId);
}

-(void)sendDataToA:(NSString *)myStringData
{

    NSLog(@"Inside sendDataToA");
    UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"Your string Data Showing" message:myStringData delegate:self cancelButtonTitle:@"Ok " otherButtonTitles:nil];
    [alert show];
}

- (IBAction)gotoBViewController:(id)sender {
    NSLog(@"pressed");
    BIDAddTypeOfDealViewController *bidAddType = [[BIDAddTypeOfDealViewController alloc]init];
    bidAddType.delegate = self;

}
@end


@protocol senddataProtocol <NSObject>
-(void)sendDataToA:(NSString *)myStringData;
@end

#import <UIKit/UIKit.h>
@interface BIDAddTypeOfDealViewController : UIViewController <UITextFieldDelegate>//Using this delegate for data a user inputs
@property(nonatomic,assign)id delegate;
//other textfield outlets not relevant
- (IBAction)chooseDiscountDeal:(id)sender;
@end

#import "BIDAddTypeOfDealViewController.h"

@interface BIDAddTypeOfDealViewController ()

@end

@implementation BIDAddTypeOfDealViewController
@synthesize delegate;

- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
    self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
    if (self) {
        // Custom initialization
    }
    return self;
}

- (void)viewDidLoad
{
    [super viewDidLoad];
}

-(void)viewWillDisappear:(BOOL)animated
{
    [delegate sendDataToA:@"Apple"];
}
@end

回答by Erhan Demirci

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.

您可以使用委托。因此,在您的 ViewController B 中,您需要创建一个将数据发送回您的 ViewController A 的协议。您的 ViewController A 将成为 ViewController B 的委托。

If you are new to objective C, please look at What is Delegate.

如果您不熟悉目标 C,请查看什么是委托

Create protocol in ViewControllerB.h :

在 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

视图控制器B.m

@synthesize delegate;
-(void)viewWillDisappear:(BOOL)animated
{
     [delegate sendDataToA:yourdata];

}

in your ViewControllerA : when you go to ViewControllerB

在您的 ViewControllerA 中:当您转到 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

你可以看到这个例子:How you can pass data back to previous viewcontroller:教程链接

回答by Heinrisch

A shorter and simplermethod than protocol/delegate is to create a closure:

短和更简单的比协议/委托方法是创建一个闭合:

For sending a String back in my case. In ViewControllerA:

在我的情况下发回一个字符串。在 ViewControllerA 中:

override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
    if let viewControllerB = segue.destination as? ViewControllerB {
        viewControllerB.callback = { message in
            //Do what you want in here!
        }
    }
}

In ViewControllerB:

在 ViewControllerB 中:

var callback : ((String) -> Void)?

@IBAction func done(sender: AnyObject) {
    callback?("Hi")
    self.dismiss(animated: true, completion: nil)
}

回答by Suragch

Swift: Sending data back using the delegate pattern

Swift:使用委托模式发回数据

My full answer that covers passing data both ways is here. My answer explaining the delegate pattern is here.

我完整的答案,涵盖传递数据两种方式是在这里。我解释委托模式的答案在这里

To pass data back from the second view controller to the first view controller, you use a protocol and a delegate. This video is a very clear walk though of that process:

要将数据从第二个视图控制器传递回第一个视图控制器,您需要使用协议和委托。这个视频是一个非常清晰的过程:

The following is an example based on the video (with a few modifications).

以下是基于视频的示例(有一些修改)。

enter image description here

在此处输入图片说明

Create the storyboard layout in the Interface Builder. Again, to make the segue, you just Controldrag from the button to the Second View Controller. Set the segue identifier to showSecondViewController. Also, don't forget to hook up the outlets and actions using the names in the following code.

在界面生成器中创建故事板布局。再次,为了进行转场,您只需Control从按钮拖动到第二个视图控制器。将 segue 标识符设置为showSecondViewController. 另外,不要忘记使用以下代码中的名称连接插座和动作。

First View Controller

第一个视图控制器

The code for the First View Controller is

第一个视图控制器的代码是

import UIKit

class FirstViewController: UIViewController, DataEnteredDelegate {

    @IBOutlet weak var label: UILabel!

    override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
        if segue.identifier == "showSecondViewController" {
            let secondViewController = segue.destinationViewController as! SecondViewController
            secondViewController.delegate = self
        }
    }

    func userDidEnterInformation(info: String) {
        label.text = info
    }
}

Note the use of our custom DataEnteredDelegateprotocol.

请注意我们自定义DataEnteredDelegate协议的使用。

Second View Controller and Protocol

第二个视图控制器和协议

The code for the second view controller is

第二个视图控制器的代码是

import UIKit

// protocol used for sending data back
protocol DataEnteredDelegate: class {
    func userDidEnterInformation(info: String)
}

class SecondViewController: UIViewController {

    // making this a weak variable so that it won't create a strong reference cycle
    weak var delegate: DataEnteredDelegate? = nil

    @IBOutlet weak var textField: UITextField!

    @IBAction func sendTextBackButton(sender: UIButton) {

        // call this method on whichever class implements our delegate protocol
        delegate?.userDidEnterInformation(textField.text!)

        // go back to the previous view controller
        self.navigationController?.popViewControllerAnimated(true)
    }
}

Note that the protocolis outside of the View Controller class.

请注意,protocol是在视图控制器类之外。

That's it. Running the app now you should be able to send data back from the second view controller to the first.

就是这样。现在运行应用程序,您应该能够将数据从第二个视图控制器发送回第一个。

回答by Akshit Zaveri

Edit:Use @Erhan's solution above. Not this one. This is not a good solution.

编辑:使用上面@Erhan 的解决方案。不是这个。这不是一个好的解决方案。

This will help. Write this in your ViewControllerB.

这会有所帮助。将此写入您的 ViewControllerB。

    // Get array of current navigation stack
    NSArray *arrayViewControllers = [self.navigationController viewControllers];

    // Get previous viewController object from it
    YOUR_VIEW_CONTROLLER_NAME *objViewController = (YOUR_VIEW_CONTROLLER_NAME *)[arrayViewControllers objectAtIndex:arrayViewControllers.count-2];

    // For safety this check is needed. whether it the class that you want or not.
    if ([objViewController isKindOfClass:[YOUR_VIEW_CONTROLLER_NAME class]])
    {
        // Access properties of YOUR_VIEW_CONTROLLER_NAME here
        objViewController.yourProperty = YOUR_VALUE;
    }

回答by Abdullah Umer

As Erhan Demirci answered, you can use delegates. Delegates are helpful when you want to pass data to a single view controller.

正如 Erhan Demirci 回答的那样,您可以使用委托。当您想将数据传递给单个视图控制器时,委托很有用。

NSNotificationCenteris another convenient way to transfer data between viewcontrollers/objects. This is very helpful in broadcasting data within the application.

NSNotificationCenter是另一种在视图控制器/对象之间传输数据的便捷方式。这对于在应用程序中广播数据非常有帮助。

read documentation here.

在这里阅读文档。

回答by Saurabh Sharma

Custom delegate is the best option to move data but you can try this also.

自定义委托是移动数据的最佳选择,但您也可以尝试这样做。

You can use NSUserDefaults for Moving the data any where you want.

您可以使用 NSUserDefaults 将数据移动到任何您想要的位置。

Swift 3 Code

斯威夫特 3 代码

UserDefaults.standard.set(<Value>, forKey: <Key>) 
// To set data

UserDefaults.standard.object(forKey: <Key>) 
// To get data

You can also use NSNotification for move data.

您还可以使用 NSNotification 来移动数据。

NotificationCenter.default.post(name: Notification.Name(rawValue: "refresh"), object: myDict) 

NotificationCenter.default.addObserver(self, selector: #selector(refreshList(_:)), name: NSNotification.Name(rawValue: "refresh"), object: nil)

回答by John Pang

There is protocol there is closure. With closure, we need to avoid memory leaks by using weak self (or unowned self). With protocol, there would be one per viewController that you want to "monitor", end up with dozens of delegate to implement. Here I've another simple solutions in Swift:

有协议就有关闭。使用闭包,我们需要通过使用弱自我(或无主自我)来避免内存泄漏。使用协议,每个 viewController 将有一个要“监视”,最终需要实现数十个委托。在这里,我在 Swift 中有另一个简单的解决方案:

Inside a new file or existing one (for example: UIViewController+Extensions.swift), create this protocol:

在新文件或现有文件中(例如:)UIViewController+Extensions.swift,创建此协议:

protocol ViewControllerBackDelegate: class {
    func back(from viewController: UIViewController)
}

Inside LEVEL-2 viewController, where you want a callback when Back is pressed from:

在 LEVEL-2 viewController 中,当按下 Back 时你想要一个回调:

class LevelTwoViewController: UIViewController {
    // making this a weak variable so that it won't create a strong reference cycle
    weak var delegate: ViewControllerBackDelegate? = nil

    override func willMove(toParentViewController parent: UIViewController?) {
        super.willMove(toParentViewController: parent)
        if (parent == nil) {
            delegate?.back(from: self)
        }
    }
}

Since delegateis optional, you may add this code to a base class of your view controllers. I would add to where it needs to be.

由于delegate是可选的,您可以将此代码添加到视图控制器的基类中。我会添加到它需要的地方。

In your LEVEL-1 viewController, assume you calling LEVEL-2 via a segue in Storyboard:

在 LEVEL-1 viewController 中,假设您通过 Storyboard 中的 segue 调用 LEVEL-2:

class LevelOneViewController: UIViewController {
    override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
        if (segue.identifier == "Go to Level 2") {
            if let vc = segue.destination as? LevelTwoViewController {
                vc.selectedItems = self.selectedItems // passing data-in
                vc.delegate = self
            }
        }
        // repeat `if` for another sub-level view controller
    }
}

extension LevelOneViewController: ViewControllerBackDelegate {    
    func back(from viewController: UIViewController) {
        if let vc = viewController as? LevelTwoViewController {
            self.selectedItems = vc.selectedItems
            // call update if necessary
        }
        // repeat `if` for another sub-level view controller
    }
}
  • only one protocol is required.
  • only one extension per first-level viewController.
  • no modifications to sub-level viewController if more/less data need to return
  • handle data-out just like data-in in prepare(for:sender:)
  • 只需要一种协议。
  • 每个第一级 viewController 只有一个扩展。
  • 如果需要返回更多/更少的数据,则无需修改子级 viewController
  • 像数据输入一样处理数据输出 prepare(for:sender:)

回答by Paulpjmmchugh

Here is how I would do it.

这是我将如何做到的。

@interface ViewControllerA:UIViewController
@property(strong, nonatomic) ViewControllerB * recieverB;
@end

@implementation ViewControllerA
//implement class
- (void)prepareForSegue:(UIStoryboardSegue *) sender:(id)sender
{
segue.destinationViewController.recieverA = self;
}
-(void)viewDidLoad
{
//stop strong refrence cycle
self.viewControllerB = nil;
}
@end

Class B

B级

@interface ViewControllerB:UIViewController
@property(strong, nonatomic, getter = parentClass) ViewControllerB * recieverA;
@end

@implementation ViewControllerB
//implement class
- (void)viewWillDisappear:(BOOL)animated
{
parentClass.recieverB = self;
//now class A will have an instance on class b
}
@end

I didn't put the #import

我没有把#import