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

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

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

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

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


当前回答

这是一个非常棒的教程,适合任何想要的人。下面是示例代码:

- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
    if ([segue.identifier isEqualToString:@"myIdentifer]) {
        NSIndexPath *indexPath = [self.tableView indexPathForSelectedRow];
        myViewController *destViewController = segue.destinationViewController;
        destViewController.name = [object objectAtIndex:indexPath.row];
    }
}

其他回答

用于UIKit和AppKit的Pure Combine解决方案

让我们举一个简单的例子,在ViewControllers之间传递计数的Int值。

父ViewController(VC)有一个名为count的变量,子ViewController可以让用户更改count的值。一旦用户完成了值的更改,他们将关闭子控制器,然后父VC应该具有更新的值。


父视图控制器

ParentVC从ChildVC获取计数的更新值

class ParentVC: UIViewController {
    var count = 1
    var countObserver: AnyCancellable! // 1

    override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
        let childVC = segue.destination as! ChildVC
        childVC.sliderValue = count // 2
        countObserver = childVC.$sliderValue // 3
            .assign(to: \.count, on: self)
    }
}

countObserver将保留观察ChildVC所做更改的观察者当子级出现时,我们将当前的计数值从父级分配给ChildVC中的一个控件(这里是UISlider),这成为修改计数值的起点。我们观察到sliderValue(它是一个发布者),它会发出用户通过拖动滑块更改的计数值。请注意,我们使用了$sliderValue而不仅仅是sliderValue。


子视图控制器

ChildVC是发出ParentVC感兴趣的值的一个:

class ChildVC: UIViewController {
    @Published var sliderValue: Int = 0 // 1

    @IBOutlet var sliderOutlet: UISlider!

    @IBAction func slided(_ sender: UISlider) {
        sliderValue = Int(sender.value)
    }
}

@Published是存储值并在值更改时发出信号的Publisher。它的行为类似于常规变量,但可以发布可以通过在其前面加上$符号来访问的值。


CurrentValueSubject和PassthroughSubject与@Published

还可以使用CurrentValueSubject代替@Published。唯一的区别是,你必须手动发出信号。在希望控制何时发射的情况下,它非常有用。例如,您可以发射该值,但前提是该值在特定范围内。PassthroughSubject也可以代替@Published或CurrentValueSubject。这里的区别是PassthroughSubject不能保存值,它只能发出信号。当无法在变量中具体表示值时,这可能很有用。

苹果公司的一种方法是使用Segues。您需要使用prepareForSegue()函数。

有很多很棒的教程,这里有一个:释放你的内部应用程序开发人员第21部分:在控制器之间传递数据

此外,请阅读有关使用segues的Apple文档:使用Segues

在下一个视图controller.h文件中创建属性,并定义getter和setter。

在NextVC上的NextVC.h中添加此属性:

@property (strong, nonatomic) NSString *indexNumber;

Add

@综合索引编号;在NextVC.m中

最后一个

NextVC *vc = [[NextVC alloc]init];

vc.indexNumber = @"123";

[self.navigationController vc animated:YES];

在使用.xib文件时,委派是执行此类操作的唯一解决方案。然而,之前的所有答案都是针对.xib文件的脚本。你需要使用授权。这是您可以使用的唯一解决方案。

另一个解决方案是使用单例类模式。初始化一次并在整个应用程序中使用它。

这不是这样做的。你应该使用委托。

我假设我们有两个视图控制器,ViewController1和ViewController2,这个检查是在第一个视图控制器中,当它的状态发生变化时,您需要在ViewController2中执行一些操作。为了以正确的方式实现这一点,您应该执行以下操作:

向项目添加新文件(Objective-C协议)菜单文件→ 新现在将其命名为ViewController1Delegate或任何您想要的名称,并在@interface和@end指令之间编写这些命令:

@optional

- (void)checkStateDidChange:(BOOL)checked;

现在转到ViewController2.h并添加:

#import "ViewController1Delegate.h"

然后将其定义更改为:

@interface ViewController2: UIViewController<ViewController1Delegate>

现在转到ViewController2.m,在实现中添加:

- (void)checkStateDidChange:(BOOL)checked {
     if (checked) {
           // Do whatever you want here
           NSLog(@"Checked");
     }
     else {
           // Also do whatever you want here
           NSLog(@"Not checked");
     }
}

现在转到ViewController1.h并添加以下属性:

@property (weak, nonatomic) id<ViewController1Delegate> delegate;

现在,如果您在某个事件后在ViewController2内创建ViewController1,那么您应该使用NIB文件这样做:

ViewController1* controller = [[NSBundle mainBundle] loadNibNamed:@"ViewController1" owner:self options:nil][0];
controller.delegate = self;
[self presentViewController:controller animated:YES completion:nil];

现在你都准备好了。每当您检测到ViewController1中的检查事件发生更改时,您只需执行以下操作:

[delegate checkStateDidChange:checked]; // You pass here YES or NO based on the check state of your control