我对iOS和Objective-C以及整个MVC范式都是新手,我一直坚持以下几点:
我有一个充当数据输入表单的视图,我想让用户选择多个产品。产品列在另一个具有UITableViewController的视图中,我已启用多个选项。
如何将数据从一个视图传输到另一个视图?我会将UITableView上的选择保存在一个数组中,但如何将其传递回上一个数据输入表单视图,以便在提交表单时将其与其他数据一起保存到核心数据?
我在网上冲浪,看到一些人在应用程序委托中声明了一个数组。我读了一些关于单态的东西,但我不明白这些是什么,我读了关于创建数据模型的东西。
正确的执行方式是什么?我将如何执行?
使用通知中心
对于Swift 3
let imageDataDict:[String: UIImage] = ["image": image]
// Post a notification
NotificationCenter.default.post(name: NSNotification.Name(rawValue: "notificationName"), object: nil, userInfo: imageDataDict)
// `default` is now a property, not a method call
// Register to receive notification in your class
NotificationCenter.default.addObserver(self, selector: #selector(self.showSpinningWheel(_:)), name: NSNotification.Name(rawValue: "notificationName"), object: nil)
// Handle notification
func showSpinningWheel(_ notification: NSNotification) {
print(notification.userInfo ?? "")
if let dict = notification.userInfo as NSDictionary? {
if let id = dict["image"] as? UIImage {
// Do something with your image
}
}
}
对于Swift 4
let imageDataDict:[String: UIImage] = ["image": image]
// Post a notification
NotificationCenter.default.post(name: NSNotification.Name(rawValue: "notificationName"), object: nil, userInfo: imageDataDict)
// `default` is now a property, not a method call
// Register to receive notification in your class
NotificationCenter.default.addObserver(self, selector: #selector(self.showSpinningWheel(_:)), name: NSNotification.Name(rawValue: "notificationName"), object: nil)
// Handle notification
@objc func showSpinningWheel(_ notification: NSNotification) {
print(notification.userInfo ?? "")
if let dict = notification.userInfo as NSDictionary? {
if let id = dict["image"] as? UIImage {
// Do something with your image
}
}
}
我找到了最简单、最优雅的版本,带有传递块。让我们将等待返回数据的视图控制器命名为“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);
需要记住的一点是,使用块通常需要管理强引用和弱引用,如这里所述
我目前正在通过一个名为MCViewFactory的项目为这个问题的开源解决方案做出贡献,这个项目可以在这里找到:
Manticore iOS视图工厂
其想法是模仿Android的意图范式,使用全局工厂来管理您正在查看的视图,并使用“意图”在视图之间切换和传递数据。所有文档都在GitHub页面上,但这里有一些亮点:
初始化工厂时,在.XIB文件中设置所有视图并在应用程序委托中注册它们。
// Register activities
MCViewFactory *factory = [MCViewFactory sharedFactory];
// The following two lines are optional.
[factory registerView:@"YourSectionViewController"];
现在,在视图控制器(VC)中,只要您想移动到新的VC并传递数据,就可以创建一个新的意图并将数据添加到其字典(savedInstanceState)中。然后,只需设置工厂的当前意图:
MCIntent* intent = [MCIntent intentWithSectionName:@"YourSectionViewController"];
[intent setAnimationStyle:UIViewAnimationOptionTransitionFlipFromLeft];
[[intent savedInstanceState] setObject:@"someValue" forKey:@"yourKey"];
[[intent savedInstanceState] setObject:@"anotherValue" forKey:@"anotherKey"];
// ...
[[MCViewModel sharedModel] setCurrentSection:intent];
所有符合此要求的视图都需要是MCViewController的子类,它允许您重写新的onResume:方法,允许您访问传入的数据。
-(void)onResume:(MCIntent *)intent {
NSObject* someValue = [intent.savedInstanceState objectForKey:@"yourKey"];
NSObject* anotherValue = [intent.savedInstanceState objectForKey:@"anotherKey"];
// ...
// Ensure the following line is called, especially for MCSectionViewController
[super onResume:intent];
}