我对iOS和Objective-C以及整个MVC范式都是新手,我一直坚持以下几点:

我有一个充当数据输入表单的视图,我想让用户选择多个产品。产品列在另一个具有UITableViewController的视图中,我已启用多个选项。

如何将数据从一个视图传输到另一个视图?我会将UITableView上的选择保存在一个数组中,但如何将其传递回上一个数据输入表单视图,以便在提交表单时将其与其他数据一起保存到核心数据?

我在网上冲浪,看到一些人在应用程序委托中声明了一个数组。我读了一些关于单态的东西,但我不明白这些是什么,我读了关于创建数据模型的东西。

正确的执行方式是什么?我将如何执行?


当前回答

这里有一个更简单的方法。

只需使用全局变量。声明传递给下一个类所需的对象或变量。

例如,我们有两个类-类A和类B。

在类A中,通常包含:

#import "classA.h"

@interface classA()

@end

@implementation classA

-(void)viewDidLoad
{
    ...
}
-(void)didReceiveMemoryWarning
{
    ...
}

B类包含:

#import "classB.h"

@interface classB()

@end

@implementation classB

-(void)viewWillLoad
{
    ...
}
-(void)didReceiveMemoryWarning
{
    ...
}

现在,将第二个类classB导入classA:

#import "classA.h"
#import "classB.h"  // --- Import classB to classA.
@interface classA()

@end

@implementation classA

-(void)viewDidLoad
{
    ...
}
-(void)didReceiveMemoryWarning
{
    ...
}

现在我们有一座桥去二等B班。现在,要将变量或对象声明为全局变量,请在第一个类的.m文件中声明它,如下所示:

在A.h类中

#import "classA.h"
#import "classB.h"
@interface classA()

@end
NSString *temp;  // ---- Declare any object/variable as global.
@implementation classA

-(void)viewDidLoad
{
    ...
    temp=@"Hello";
    ...
}
-(void)didReceiveMemoryWarning
{
    ...
}

这里,对象temp是NSString类的全局对象。要访问任何类中的全局对象或变量,只需在第二个类中重新声明对象或变量。例如,如下所示:

在B.m类中

#import "classB.h"

@interface classB()

@end
extern NSString *temp;  //----use `extern` keyword for using the global object/variable in classB that was declared in classA.
@implementation classB

-(void)viewDidLoad
{
    ...
    LabeL.text=temp;
    ...
}
-(void)didReceiveMemoryWarning
{
    ...
}

现在,第二个类可以访问该值。易于理解的此方法可用于任意数量的类。

注:

您应该将第二个类的.h文件导入到第一个类。但不需要进口将第一类的.h文件转换为第二类。

记住那座桥。如果有一座桥,它应该可以从两边走。

其他回答

共享数据有多种方法。

您始终可以使用NSUserDefaults共享数据。设置要与所选键共享的值,并在下一个视图控制器中从与该键关联的NSUserDefault获取值。[[NSUserDefaults standardUserDefaults]setValue:key:key的值][[NSUserDefaults standardUserDefaults]objectForKey:key]您只需在viewcontrollerA中创建一个属性。在viewcontrollerB中创建viewcontrollerA的对象,并为该属性分配所需的值。您也可以为此创建自定义代理。

在我的例子中,我使用了一个单例类,它可以作为一个全局对象,允许访问应用程序中几乎所有地方的数据。

第一件事是构建一个单例类。请参考页面我的Objective-C单例应该是什么样子?。

为了使对象全局可访问,我只需将其导入appName_Prefix.pch中,该程序用于在每个类中应用import语句。

为了访问和使用这个对象,我简单地实现了一个类方法来返回共享实例,该实例包含自己的变量。

雨燕5Matt Price的回答非常适合传递数据,但我我将在最新的Swift版本中重写它,因为我相信由于新的语法和方法/框架,正如最初的帖子在Objective-C中那样。

在视图控制器之间传递数据有多种选项。

使用导航控制器推送使用Segue使用代理使用通知查看器使用块

我将用最新的iOS框架在Swift中重写他的逻辑


通过导航控制器传递数据推送:从ViewControllerA到ViewControllerB

步骤1。在ViewControllerB中声明变量

var isSomethingEnabled = false

步骤2。在ViewControllerB的ViewDidLoad方法中打印变量

override func viewDidLoad() {
    super.viewDidLoad()
    // Print value received through segue, navigation push
    print("Value of 'isSomethingEnabled' from ViewControllerA: ", isSomethingEnabled)
}

步骤3。在ViewControllerA中通过导航控制器时传递数据

if let viewControllerB = UIStoryboard(name: "Main", bundle: nil).instantiateViewController(withIdentifier: "ViewControllerB") as? ViewControllerB {
    viewControllerB.isSomethingEnabled = true
    if let navigator = navigationController {
        navigator.pushViewController(viewControllerB, animated: true)
    }
}

以下是完整的代码:

视图控制器A

import UIKit

class ViewControllerA: UIViewController  {

    override func viewDidLoad() {
        super.viewDidLoad()
    }

    // MARK: Passing data through navigation PushViewController
    @IBAction func goToViewControllerB(_ sender: Any) {

        if let viewControllerB = UIStoryboard(name: "Main", bundle: nil).instantiateViewController(withIdentifier: "ViewControllerB") as? ViewControllerB {
            viewControllerB.isSomethingEnabled = true
            if let navigator = navigationController {
                navigator.pushViewController(viewControllerB, animated: true)
            }
        }
    }
}

视图控制器B

import UIKit

class ViewControllerB: UIViewController {

    // MARK:  - Variable for Passing Data through Navigation push
    var isSomethingEnabled = false

    override func viewDidLoad() {
        super.viewDidLoad()
        // Print value received through navigation push
        print("Value of 'isSomethingEnabled' from ViewControllerA: ", isSomethingEnabled)
    }
}

通过Segue传递数据:从ViewControllerA到ViewControllerB

步骤1。创建从ViewControllerA到ViewControllerB的Segue,并在Storyboard中提供Identifier=showDetailSegue,如下所示

步骤2。在ViewControllerB中声明一个名为isSomethingEnabled的可行值并打印其值。

步骤3。在ViewControllerA中,传递Segue时传递SomethingEnabled的值

以下是完整的代码:

视图控制器A

import UIKit

class ViewControllerA: UIViewController  {

    override func viewDidLoad() {
        super.viewDidLoad()
    }

    // MARK:  - - Passing Data through Segue  - -
    @IBAction func goToViewControllerBUsingSegue(_ sender: Any) {
        performSegue(withIdentifier: "showDetailSegue", sender: nil)
    }

    // Segue Delegate Method
    override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
        if (segue.identifier == "showDetailSegue") {
            let controller = segue.destination as? ViewControllerB
            controller?.isSomethingEnabled = true//passing data
        }
    }
}

视图控制器B

import UIKit

class ViewControllerB: UIViewController {
    var isSomethingEnabled = false

    override func viewDidLoad() {
        super.viewDidLoad()
        // Print value received through segue
        print("Value of 'isSomethingEnabled' from ViewControllerA: ", isSomethingEnabled)
    }
}

通过委托传递数据:从ViewControllerB到ViewControllerA

步骤1。在ViewControllerB文件中声明协议ViewControllerBDlegate,但在类之外

protocol ViewControllerBDelegate: NSObjectProtocol {

    // Classes that adopt this protocol MUST define
    // this method -- and hopefully do something in
    // that definition.
    func addItemViewController(_ controller: ViewControllerB?, didFinishEnteringItem item: String?)
}

步骤2。在ViewControllerB中声明委托变量实例

var delegate: ViewControllerBDelegate?

步骤3。在ViewControllerB的viewDidLoad方法中发送委托的数据

delegate?.addItemViewController(self, didFinishEnteringItem: "Data for ViewControllerA")

步骤4。确认ViewControllerB在ViewControllerA中保留

class ViewControllerA: UIViewController, ViewControllerBDelegate  {
// to do
}

步骤5。确认将在ViewControllerA中实现委托

if let viewControllerB = UIStoryboard(name: "Main", bundle: nil).instantiateViewController(withIdentifier: "ViewControllerB") as? ViewControllerB {
    viewControllerB.delegate = self//confirming delegate
    if let navigator = navigationController {
        navigator.pushViewController(viewControllerB, animated: true)
    }
}

步骤6。实现用于在ViewControllerA中接收数据的委托方法

func addItemViewController(_ controller: ViewControllerB?, didFinishEnteringItem item: String?) {
    print("Value from ViewControllerB's Delegate", item!)
}

以下是完整的代码:

视图控制器A

import UIKit

class ViewControllerA: UIViewController, ViewControllerBDelegate  {

    override func viewDidLoad() {
        super.viewDidLoad()
    }

    // Delegate method
    func addItemViewController(_ controller: ViewControllerB?, didFinishEnteringItem item: String?) {
        print("Value from ViewControllerB's Delegate", item!)
    }

    @IBAction func goToViewControllerForDelegate(_ sender: Any) {

        if let viewControllerB = UIStoryboard(name: "Main", bundle: nil).instantiateViewController(withIdentifier: "ViewControllerB") as? ViewControllerB {
            viewControllerB.delegate = self
            if let navigator = navigationController {
                navigator.pushViewController(viewControllerB, animated: true)
            }
        }
    }
}

视图控制器B

import UIKit

//Protocol decleare
protocol ViewControllerBDelegate: NSObjectProtocol {
    // Classes that adopt this protocol MUST define
    // this method -- and hopefully do something in
    // that definition.
    func addItemViewController(_ controller: ViewControllerB?, didFinishEnteringItem item: String?)
}

class ViewControllerB: UIViewController {
    var delegate: ViewControllerBDelegate?

    override func viewDidLoad() {
        super.viewDidLoad()
        // MARK:  - - - -  Set Data for Passing Data through Delegate  - - - - - -
        delegate?.addItemViewController(self, didFinishEnteringItem: "Data for ViewControllerA")
    }
}

通过通知查看器传递数据:从ViewControllerB到ViewControllerA

步骤1。在ViewControllerB中的通知查看器中设置和发布数据

let objToBeSent = "Test Message from Notification"
        NotificationCenter.default.post(name: Notification.Name("NotificationIdentifier"), object: objToBeSent)

步骤2。在ViewControllerA中添加通知查看器

NotificationCenter.default.addObserver(self, selector: #selector(self.methodOfReceivedNotification(notification:)), name: Notification.Name("NotificationIdentifier"), object: nil)

步骤3。在ViewControllerA中接收通知数据值

@objc func methodOfReceivedNotification(notification: Notification) {
    print("Value of notification: ", notification.object ?? "")
}

以下是完整的代码:

视图控制器A

import UIKit

class ViewControllerA: UIViewController{

    override func viewDidLoad() {
        super.viewDidLoad()

        // Add observer in controller(s) where you want to receive data
        NotificationCenter.default.addObserver(self, selector: #selector(self.methodOfReceivedNotification(notification:)), name: Notification.Name("NotificationIdentifier"), object: nil)
    }

    // MARK: Method for receiving Data through Post Notification
    @objc func methodOfReceivedNotification(notification: Notification) {
        print("Value of notification: ", notification.object ?? "")
    }
}

视图控制器B

import UIKit

class ViewControllerB: UIViewController {

    override func viewDidLoad() {
        super.viewDidLoad()

        // MARK:Set data for Passing Data through Post Notification
        let objToBeSent = "Test Message from Notification"
        NotificationCenter.default.post(name: Notification.Name("NotificationIdentifier"), object: objToBeSent)
    }
}

通过块传递数据:从ViewControllerB到ViewControllerA

步骤1。在ViewControllerB中声明块

var authorizationCompletionBlock:((Bool)->())? = {_ in}

步骤2。在ViewControllerB中设置块中的数据

if authorizationCompletionBlock != nil
{
    authorizationCompletionBlock!(true)
}

步骤3。在ViewControllerA中接收块数据

// Receiver Block
controller!.authorizationCompletionBlock = { isGranted in
    print("Data received from Block is: ", isGranted)
}

以下是完整的代码:

视图控制器A

import UIKit

class ViewControllerA: UIViewController  {

    override func viewDidLoad() {
        super.viewDidLoad()
    }

    // MARK:Method for receiving Data through Block
    override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
        if (segue.identifier == "showDetailSegue") {
            let controller = segue.destination as? ViewControllerB
            controller?.isSomethingEnabled = true

            // Receiver Block
            controller!.authorizationCompletionBlock = { isGranted in
                print("Data received from Block is: ", isGranted)
            }
        }
    }
}

视图控制器B

import UIKit

class ViewControllerB: UIViewController {

    // MARK: Variable for Passing Data through Block
    var authorizationCompletionBlock:((Bool)->())? = {_ in}

    override func viewDidLoad() {
        super.viewDidLoad()

        // MARK: Set data for Passing Data through Block
        if authorizationCompletionBlock != nil
        {
            authorizationCompletionBlock!(true)
        }
    }
}

你可以在我的GitHub上找到完整的示例应用程序。如果你对此有任何疑问,请告诉我。

如果要将数据从ViewControlerOne传递到ViewControlerTwo,请尝试以下操作。。。

在ViewControlerOne.h中执行以下操作:

 @property (nonatomic, strong) NSString *str1;

在ViewControllerTwo.h中执行以下操作:

 @property (nonatomic, strong) NSString *str2;

在ViewControllerTwo.m中合成str2:

@interface ViewControllerTwo ()
@end
@implementation ViewControllerTwo
@synthesize str2;

在ViewControlerOne.m中执行以下操作:

 - (void)viewDidLoad
 {
   [super viewDidLoad];

   // Data or string you wants to pass in ViewControllerTwo...
   self.str1 = @"hello world";
 }

O按钮单击事件,请执行以下操作:

-(IBAction)ButtonClicked
{
  // Navigation on buttons click event from ViewControlerOne to ViewControlerTwo with transferring data or string..
  ViewControllerTwo *objViewTwo = [self.storyboard instantiateViewControllerWithIdentifier:@"ViewControllerTwo"];
  obj.str2 = str1;
  [self.navigationController pushViewController: objViewTwo animated:YES];
}

在ViewControllerTwo.m中执行以下操作:

- (void)viewDidLoad
{
  [super viewDidLoad];
  NSLog(@"%@", str2);
}

敏捷的

这里和Stack Overflow周围有很多解释,但如果你是一个初学者,只是想做一些基本的工作,那么试试看YouTube教程(它帮助我最终了解了如何做)。

YouTube教程:如何通过segue发送数据(Swift)

将数据转发给下一个视图控制器

以下是基于视频的示例。其思想是将一个字符串从第一视图控制器中的文本字段传递到第二视图控制器的标签。

在界面生成器中创建情节提要布局。要制作segue,只需Control单击按钮并拖动到“第二视图控制器”。

第一视图控制器

第一视图控制器的代码为

import UIKit

class FirstViewController: UIViewController {

    @IBOutlet weak var textField: UITextField!

    // This function is called before the segue
    override func prepare(for segue: UIStoryboardSegue, sender: Any?) {

        // Get a reference to the second view controller
        let secondViewController = segue.destination as! SecondViewController

        // Set a variable in the second view controller with the String to pass
        secondViewController.receivedString = textField.text!
    }

}

第二视图控制器

第二视图控制器的代码是

import UIKit

class SecondViewController: UIViewController {

    @IBOutlet weak var label: UILabel!

    // This variable will hold the data being passed from the First View Controller
    var receivedString = ""

    override func viewDidLoad() {
        super.viewDidLoad()

        // Used the text from the First View Controller to set the label
        label.text = receivedString
    }

}

别忘了

连接UITextField和UILabel的插座。在Interface Builder中将第一个和第二个视图控制器设置为相应的Swift文件。

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

要将数据从第二个视图控制器传递回第一个视图控制器,请使用协议和代理。本视频非常清晰地介绍了这一过程:

YouTube教程:iOS Swift基础教程:协议和委托但也要阅读这篇文章,以确保您不会陷入强大的参考循环。

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

在界面生成器中创建情节提要布局。同样,要制作segue,只需按住Ctrl键将其从按钮拖动到“第二视图控制器”。将segue标识符设置为showSecondViewController。此外,不要忘记使用以下代码中的名称连接出口和操作。

第一视图控制器

第一视图控制器的代码为

import UIKit

class FirstViewController: UIViewController, DataEnteredDelegate {

    @IBOutlet weak var label: UILabel!

    override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
        if segue.identifier == "showSecondViewController" {
            let secondViewController = segue.destination as! SecondViewController
            secondViewController.delegate = self
        }
    }

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

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

第二视图控制器和协议

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

import UIKit

// Protocol used for sending data back
protocol DataEnteredDelegate: AnyObject {
    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: AnyObject) {

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

        // Go back to the previous view controller
        _ = self.navigationController?.popViewController(animated: true)
    }
}

请注意,该协议在View Controller类之外。

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