在视图控制器之间传递数据
我是iOS和Objective-C以及整个MVC范例的新手,我坚持以下几点:
我有一个视图用作数据输入表单,我想让用户选择多个产品。 使用UITableViewController
将产品列在另一个视图中,并且已启用多个选择。
我的问题是,如何将数据从一个视图传输到另一个视图? 我将在数组中保存UITableView
的选择,但是如何将它们传递回先前的数据输入表单视图,以便在提交表单时将其与其他数据一起保存到核心数据中?
我浏览过周围,看到有些人在应用程序委托中声明了一个数组。 我读了一些关于单身人士的东西,但不明白这些是什么,我读了一些关于创建数据模型的东西。
执行此操作的正确方法是什么?我将如何处理它?
这个问题似乎在stackoverflow上很受欢迎,所以我想我会尝试给出一个更好的答案,以帮助像我这样的iOS开始。
我希望这个答案足够清晰,让人们明白,并且我没有遗漏任何东西。
向前传递数据
将数据从另一个视图控制器传递给视图控制器。 如果你想将一个对象/值从一个视图控制器传递到另一个视图控制器,你可能会使用这种方法。
对于这个例子,我们将有ViewControllerA
和ViewControllerB
要将ViewControllerA
的BOOL
值传递给ViewControllerB
我们将执行以下操作。
在ViewControllerB.h
为BOOL
创建一个属性
@property (nonatomic, assign) BOOL isSomethingEnabled;
在ViewControllerA
你需要告诉它关于ViewControllerB
所以使用一个
#import "ViewControllerB.h"
然后,你想加载视图,例如。 didSelectRowAtIndex
或一些IBAction
您需要先在ViewControllerB
设置属性,然后再将其推入导航堆栈。
ViewControllerB *viewControllerB = [[ViewControllerB alloc] initWithNib:@"ViewControllerB" bundle:nil];
viewControllerB.isSomethingEnabled = YES;
[self pushViewController:viewControllerB animated:YES];
这会将ViewControllerB
isSomethingEnabled
设置为BOOL
值YES
。
使用分段传递数据转发
如果你正在使用故事板,你很可能会使用segues,并且需要这个过程来传递数据。 这与上述类似,但不是在推送视图控制器之前传递数据,而是使用名为的方法
-(void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
所以要通过一个BOOL
从ViewControllerA
到ViewControllerB
我们会做到以下几点:
在ViewControllerB.h
为BOOL
创建一个属性
@property (nonatomic, assign) BOOL isSomethingEnabled;
在ViewControllerA
你需要告诉它关于ViewControllerB
所以使用一个
#import "ViewControllerB.h"
在Storyboard上创建一个从ViewControllerA
到ViewControllerB
的segue并给它一个标识符,在这个例子中,我们将它称为"showDetailSegue"
接下来,我们需要将该方法添加到在执行任何Segue时调用的ViewControllerA
,因此我们需要检测哪个segue被调用,然后执行某些操作。 在我们的例子中,我们将检查"showDetailSegue"
,如果这样做,我们将传递BOOL
值到ViewControllerB
-(void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender{
if([segue.identifier isEqualToString:@"showDetailSegue"]){
ViewControllerB *controller = (ViewControllerB *)segue.destinationViewController;
controller.isSomethingEnabled = YES;
}
}
如果您将视图嵌入到导航控制器中,则需要将上面的方法略微更改为以下方法
-(void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender{
if([segue.identifier isEqualToString:@"showDetailSegue"]){
UINavigationController *navController = (UINavigationController *)segue.destinationViewController;
ViewControllerB *controller = (ViewControllerB *)navController.topViewController;
controller.isSomethingEnabled = YES;
}
}
这会将ViewControllerB
isSomethingEnabled
设置为BOOL
值YES
。
传回数据
传递数据从背面ViewControllerB
到ViewControllerA
需要使用协议和代表或块,后者可以被用作用于回调松散耦合机制。
要做到这一点,我们将ViewControllerA
的委托ViewControllerB
。 这允许ViewControllerB
将消息发送回ViewControllerA
使我们能够发回数据。
对于ViewControllerA
是的代表ViewControllerB
它必须符合ViewControllerB
我们有指定的协议。 这告诉ViewControllerA
它必须实现哪些方法。
在ViewControllerB.h
, #import
下方,但上面的@interface
指定协议。
@class ViewControllerB;
@protocol ViewControllerBDelegate <NSObject>
- (void)addItemViewController:(ViewControllerB *)controller didFinishEnteringItem:(NSString *)item;
@end
接下来仍然在ViewControllerB.h
您需要设置一个delegate
属性并在ViewControllerB.m
合成
@property (nonatomic, weak) id <ViewControllerBDelegate> delegate;
在ViewControllerB
,当我们弹出视图控制器时,我们在delegate
上调用一条消息。
NSString *itemToPassBack = @"Pass this value back to ViewControllerA";
[self.delegate addItemViewController:self didFinishEnteringItem:itemToPassBack];
这就是ViewControllerB
。 现在在ViewControllerA.h
,告诉ViewControllerA
导入ViewControllerB
并符合它的协议。
#import "ViewControllerB.h"
@interface ViewControllerA : UIViewController <ViewControllerBDelegate>
在ViewControllerA.m
从我们的协议实现以下方法
- (void)addItemViewController:(ViewControllerB *)controller didFinishEnteringItem:(NSString *)item
{
NSLog(@"This was returned from ViewControllerB %@",item);
}
在将viewControllerB
推viewControllerB
导航堆栈之前,我们需要告诉ViewControllerB
ViewControllerA
是它的委托,否则我们会得到一个错误。
ViewControllerB *viewControllerB = [[ViewControllerB alloc] initWithNib:@"ViewControllerB" bundle:nil];
viewControllerB.delegate = self
[[self navigationController] pushViewController:viewControllerB animated:YES];
参考
迅速
这里和周围有大量的解释和StackOverflow,但如果你是一个初学者,试图让一些基本的工作,尝试看这个YouTube教程(这是什么帮助我终于明白如何做到这一点)。
将数据传递给下一个View Controller
以下是基于视频的示例。 这个想法是将字符串从第一个视图控制器的文本字段传递到第二个视图控制器中的标签。
在Interface Builder中创建故事板布局。 要进行搜寻,只需按住按钮并拖至第二个视图控制器。
第一视图控制器
第一个视图控制器的代码是
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
的插座。 将数据传递回先前的View Controller
要将数据从第二个视图控制器传回第一个视图控制器,可以使用协议和委托。 该视频非常清晰地描述了这一过程:
以下是基于视频的示例(仅做了一些修改)。
在Interface Builder中创建故事板布局。 再次,为了使segue,你只需控制从按钮拖动到第二个视图控制器。 将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: class {
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)
}
}
请注意, protocol
不在View Controller类中。
而已。 现在运行应用程序,您应该可以将数据从第二个视图控制器发送回第一个。
MVC中的M用于“模型”,而在MVC范例中,模型类的作用是管理程序的数据。 模型与视图相反 - 视图知道如何显示数据,但不知道如何处理数据,而模型知道如何处理数据的所有信息,但不知道如何显示数据。 模型可能很复杂,但它们不一定是 - 应用程序的模型可能与字符串或字典数组一样简单。
控制器的作用是在视图和模型之间进行调解。 因此,他们需要对一个或多个视图对象和一个或多个模型对象的引用。 假设你的模型是一个字典数组,每个字典代表你表中的一行。 您的应用的根视图显示该表,并且它可能负责从文件加载数组。 当用户决定向表中添加一个新行时,他们点击一些按钮,您的控制器创建一个新的(可变的)字典并将其添加到数组中。 为了填写行,控制器创建一个详细视图控制器并为其提供新的字典。 详细视图控制器填写字典并返回。 字典已经是模型的一部分,所以没有别的事情需要发生。
链接地址: http://www.djcxy.com/p/3495.html