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

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

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

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

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


当前回答

雨燕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上找到完整的示例应用程序。如果你对此有任何疑问,请告诉我。

其他回答

在FirstViewController和SecondViewController之间传递数据,如下所示

例如:

FirstViewController字符串值为

StrFirstValue = @"first";

因此,我们可以使用以下步骤在第二类中传递该值:

我们需要在SecondViewController.h文件中创建一个字符串对象NSString*strValue;需要将属性声明为.h文件中的以下声明@属性(强,非原子)NSString*strSecondValue;需要在头声明下面的FirstViewController.m文件中合成该值@合成strValue;在FirstViewController.h文件中:@属性(强,非原子)NSString*strValue;在FirstViewController中,我们从哪个方法导航到第二个视图,请在该方法中编写以下代码。SecondViewController*secondView=[[SecondViewController alloc]initWithNibName:@“SecondViewController”捆绑包:[NSBundle主捆绑包]];[secondView setStrSecondValue:StrFirstValue];[self.navigationController pushViewController:secondView动画:是];

对于SwiftUI

将@EnvironmentObject视为在许多视图上使用@ObservedObject的更聪明、更简单的方法。您不必在视图A中创建一些数据,然后将其传递给视图B、视图C和视图D,然后再最终使用它,而是可以在视图中创建数据并将其放入环境中,以便视图B、C和D可以自动访问它。

注意:环境对象必须由祖先视图提供–如果SwiftUI找不到正确类型的环境对象,则会导致崩溃。这也适用于预览,所以要小心。

例如,这里有一个存储用户设置的可观察对象:

class UserSettings: ObservableObject {
     @Published var score = 0
}

我找到了最简单、最优雅的版本,带有传递块。让我们将等待返回数据的视图控制器命名为“A”,将返回的视图控制器称为“B”。在本例中,我们希望获得两个值:第一个是Type1,第二个是Type2。

假设我们使用Storyboard,第一个控制器设置回调块,例如在segue准备期间:

- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
    if ([segue.destinationViewController isKindOfClass:[BViewController class]])
    {
        BViewController *viewController = segue.destinationViewController;

        viewController.callback = ^(Type1 *value1, Type2 *value2) {
            // optionally, close B
            //[self.navigationController popViewControllerAnimated:YES];

            // let's do some action after with returned values
            action1(value1);
            action2(value2);
        };

    }
}

和“B”视图控制器应声明回调属性BViewController.h:

// it is important to use "copy"
@property (copy) void(^callback)(Type1 *value1, Type2 *value2);

在实现文件BViewController.m中,当我们有了所需的值以返回回调时,应该调用:

if (self.callback)
    self.callback(value1, value2);

需要记住的一点是,使用块通常需要管理强引用和弱引用,如这里所述

有三种类型用于将数据从一个ViewController传递到另一个ViewControlViewController。

程序性地赛格牌手表用户默认值

演示项目链接此处-https://github.com/kamanijasmin13/Swift-Pass-data-between-viewcontrollers

程序性地

赛格牌手表

用户默认值

演示项目链接此处-https://github.com/kamanijasmin13/Swift-Pass-data-between-viewcontrollers

雨燕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上找到完整的示例应用程序。如果你对此有任何疑问,请告诉我。