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

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

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

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

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


当前回答

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

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

其他回答

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

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

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

将数据从ViewController 2(目标)传递回ViewController 1(源)是更有趣的事情。假设你使用故事板,我发现了以下所有方法:

代表通知用户默认值辛格尔顿

这些已经在这里讨论过了。

我发现有更多的方法:

使用块回调:

在VC1的prepareForSegue方法中使用它

NextViewController *destinationVC = (NextViewController *) segue.destinationViewController;
[destinationVC setDidFinishUsingBlockCallback:^(NextViewController *destinationVC)
{
    self.blockLabel.text = destination.blockTextField.text;
}];

使用故事板展开(退出)

在VC1中实现一个带有UIStoryboardSegue参数的方法,如下所示:

-(IBAction)UnWindDone:(UIStoryboardSegue *)segue { }

在故事板中,将“返回”按钮挂在vc的绿色退出按钮(展开)上。现在您有了一个“返回”的segue,因此您可以使用VC2的prepareForSegue中的destinationViewController属性在返回之前更改VC1的任何属性。

使用故事板的另一种选择Unwind(退出)-您可以使用在VC1中编写的方法-(IBAction)UnWindDone:(UIStoryboardSegue*)segue{NextViewController*NextViewController=segue.sourceViewController;self.unindLabel.text=nextViewController.undPropertyPass;}

在VC1的prepareForSegue中,您可以更改您想要共享的任何属性。

在两个展开选项中,您都可以设置按钮的标记属性,并在prepareForSegue中进行检查。

在Swift中传递数据有很多解决方案。

向前传递数据

我最喜欢的两种转发数据的方式是依赖注入(DI)和属性观察者

依赖注入

class CustomView : UIView {
    init(_ with model : Model) {
        // Do what you want with data
    }
}

财产观察员

class CustomView : UIView {
    var model : Model? {
        didSet {
            // Do what you want with data after assign data to model
        }
        willSet {
            // Do what you want with data before assign data to model
        }
    }
}

向后传递数据

还喜欢将数据传递到上一个VC/视图的方法:

协议和代表

protocol CustomViewDelegate : class {
    func addItemViewController(_ with data: Model?)
}

weak var delegate : CustomViewDelegate?

class AnotherCustomView: UIView {

     let customView = AnotherCustomView()

     init() {
         customView.delegate = self
     }
}

extention AnotherCustomView : CustomViewDelegate {
    func addItemViewController(_ with data: Model?) {
        // Do what you want with data
    }
}

关闭

class AnotherCustomView : UIView {
     init(addItem: @escaping (_ value : Model?) -> ()) {
        // Do what you want with data
     }
}

class CustomView : UIView {

    init() {
        let customView = AnotherCustomView { [weak self] model in
            // Do what you want with data
        }
    }
}

用于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不能保存值,它只能发出信号。当无法在变量中具体表示值时,这可能很有用。

MVC中的M代表“模型”,而在MVC范式中,模型类的作用是管理程序的数据。模型与视图相反——视图知道如何显示数据,但它不知道如何处理数据,而模型知道如何使用数据,但不知道如何显示。模型可能很复杂,但不一定如此——应用程序的模型可能与字符串或字典数组一样简单。

控制器的作用是在视图和模型之间进行调解。因此,它们需要对一个或多个视图对象和一个或更多模型对象的引用。假设您的模型是一个字典数组,每个字典代表表中的一行。应用程序的根视图显示该表,它可能负责从文件加载数组。当用户决定向表中添加新行时,他们点击某个按钮,控制器将创建一个新的(可变的)字典并将其添加到数组中。为了填充该行,控制器创建一个详细视图控制器并为其提供新字典。详细视图控制器填充字典并返回。字典已经是模型的一部分,因此不需要发生其他任何事情。