我对iOS和Objective-C以及整个MVC范式都是新手,我一直坚持以下几点:
我有一个充当数据输入表单的视图,我想让用户选择多个产品。产品列在另一个具有UITableViewController的视图中,我已启用多个选项。
如何将数据从一个视图传输到另一个视图?我会将UITableView上的选择保存在一个数组中,但如何将其传递回上一个数据输入表单视图,以便在提交表单时将其与其他数据一起保存到核心数据?
我在网上冲浪,看到一些人在应用程序委托中声明了一个数组。我读了一些关于单态的东西,但我不明白这些是什么,我读了关于创建数据模型的东西。
正确的执行方式是什么?我将如何执行?
将数据从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中进行检查。
如果您想将数据从一个viewController发送到另一个viewController,请使用以下方法:
假设我们有viewControllers:viewControllerA和viewControllerB
现在在文件视图ControllerB.h中
@interface viewControllerB : UIViewController {
NSString *string;
NSArray *array;
}
- (id)initWithArray:(NSArray)a andString:(NSString)s;
在文件视图ControllerB.m中:
#import "viewControllerB.h"
@implementation viewControllerB
- (id)initWithArray:(NSArray)a andString:(NSString)s {
array = [[NSArray alloc] init];
array = a;
string = [[NSString alloc] init];
string = s;
}
在文件视图ControllerA.m中:
#import "viewControllerA.h"
#import "viewControllerB.h"
@implementation viewControllerA
- (void)someMethod {
someArray = [NSArray arrayWithObjects:@"One", @"Two", @"Three", nil];
someString = [NSString stringWithFormat:@"Hahahahaha"];
viewControllerB *vc = [[viewControllerB alloc] initWithArray:someArray andString:someString];
[self.navigationController pushViewController:vc animated:YES];
[vc release];
}
因此,这就是在不设置任何委托的情况下将数据从viewControllerA传递到viewControllerB的方法。;)
用于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不能保存值,它只能发出信号。当无法在变量中具体表示值时,这可能很有用。
您可以创建一个从源视图控制器到目标视图控制器的推送段,并提供如下标识符名称。
您必须像这样执行didselectRowAt的segue。
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
performSegue(withIdentifier: "segue", sender: self)
}
您可以从下面的函数传递选定项的数组。
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
let index = CategorytableView.indexPathForSelectedRow
let indexNumber = index?.row
print(indexNumber!)
let VC = segue.destination as! AddTransactionVC
VC.val = CategoryData[indexNumber!] . // Here you can pass the entire array instead of an array element.
}
您必须检查目标viewcontroller的viewdidload中的值,然后将其存储到数据库中。
override func viewDidLoad{
if val != ""{
btnSelectCategory.setTitle(val, for: .normal)
}
}