我对iOS和Objective-C以及整个MVC范式都是新手,我一直坚持以下几点:
我有一个充当数据输入表单的视图,我想让用户选择多个产品。产品列在另一个具有UITableViewController的视图中,我已启用多个选项。
如何将数据从一个视图传输到另一个视图?我会将UITableView上的选择保存在一个数组中,但如何将其传递回上一个数据输入表单视图,以便在提交表单时将其与其他数据一起保存到核心数据?
我在网上冲浪,看到一些人在应用程序委托中声明了一个数组。我读了一些关于单态的东西,但我不明白这些是什么,我读了关于创建数据模型的东西。
正确的执行方式是什么?我将如何执行?
我建议使用块/闭包和自定义构造函数。
假设您必须将字符串从FirstViewController传递到SecondViewController。
您的第一个视图控制器。
class FirstViewController : UIViewController {
func moveToViewControllerB() {
let second_screen = SecondViewController.screen(string: "DATA TO PASS", call_back: {
[weak self] (updated_data) in
///This closure will be called by second view controller when it updates something
})
self.navigationController?.pushViewController(second_screen, animated: true)
}
}
第二个视图控制器
class SecondViewController : UIViewController {
var incoming_string : String?
var call_back : ((String) -> Void)?
class func screen(string: String?, call_back : ((String) -> Void)?) -> SecondViewController {
let me = SecondViewController(nibName: String(describing: self), bundle: Bundle.main);
me.incoming_string = string
me.call_back = call_back
return me
}
// Suppose its called when you have to update FirstViewController with new data.
func updatedSomething() {
//Executing block that is implemented/assigned by the FirstViewController.
self.call_back?("UPDATED 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不能保存值,它只能发出信号。当无法在变量中具体表示值时,这可能很有用。
有了Swift的倾向,并想要一个简单的例子,如果你使用segue来绕过,这里是我传递数据的go to方法。
它与上述类似,但没有按钮、标签等。只需将数据从一个视图传递到下一个视图。
设置情节提要
有三个部分。
发件人赛格牌手表接收者
这是一个非常简单的视图布局,中间有一个segue。
这是发件人的设置
这是接收器的设置。
最后,segue的设置。
视图控制器
我们保持这个简单,所以没有按钮,没有动作。我们只是在应用程序加载时将数据从发送方移动到接收方,然后将传输的值输出到控制台。
此页面获取初始加载的值并将其传递。
import UIKit
class ViewControllerSender: UIViewController {
// THE STUFF - put some information into a variable
let favoriteMovie = "Ghost Busters"
override func viewDidAppear(animated: Bool) {
// PASS IDENTIFIER - go to the receiving view controller.
self.performSegueWithIdentifier("goToReciever", sender: self)
}
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
// GET REFERENCE - ...to the receiver view.
var viewControllerReceiver = segue.destinationViewController as? ViewControllerReceiver
// PASS STUFF - pass the variable along to the target.
viewControllerReceiver!.yourFavMovie = self.favoriteMovie
}
}
此页面仅在加载时将变量的值发送到控制台。至此,我们最喜欢的电影应该在这个变量中。
import UIKit
class ViewControllerReceiver: UIViewController {
// Basic empty variable waiting for you to pass in your fantastic favorite movie.
var yourFavMovie = ""
override func viewDidLoad() {
super.viewDidLoad()
// And now we can view it in the console.
println("The Movie is \(self.yourFavMovie)")
}
}
如果你想使用segue,而你的页面不在导航控制器下,那么这就是解决问题的方法。
一旦运行,它应该自动切换到接收方视图,并将值从发送方传递给接收方,在控制台中显示该值。