如何使用 KVO 传递值?



我正在学习如何使用KVO。我创建了两个类,卡车和司机,如下所示。

Truck 类有一个文本字段和一个按钮,文本应包含当前的卡车速度,按下按钮时,应调用prepareForSegue,它包含下面发布的代码。

Driver 类包含一个应用卡车速度填充的文本字段。 卡车类中的卡车速度将通过 KVO 传递到驱动程序类中的文本字段,如代码所示。

我遇到的问题或我正在尝试做的是,当用户在卡车类中输入卡车的速度并按下按钮时,我想通过 KVO 显示在驱动程序类的文本字段中输入的卡车速度

根据下面发布的代码,我得到的结果是,Driver 类中的一个空文本字段

请让我知道为什么驱动程序类中的文本字段为空。 以及我应该如何通过 KVO 将卡车速度的值从卡车类传递到驱动程序类

卡车.m

#import "TruckViewController.h"
#import "DriverViewController.h"
#import "ServerViewController.h"
@interface TruckViewController ()
@property (strong, nonatomic) IBOutlet UITextField *textFieldCurrenSpeed;
@property (strong, nonatomic) IBOutlet UIButton *buttonBroadcast;
@property (strong, nonatomic) IBOutlet UIButton 
*buttonToDriverViewController;
@property (strong, nonatomic) IBOutlet UIButton   
*buttonToServerViewController;
@property (strong, nonatomic) TruckViewController *truck;
@property (strong, nonatomic) DriverViewController *driver;
@property (strong, nonatomic) ServerViewController *server;
@end

@implementation TruckViewController

- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view.
}

- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}

-(void) prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender 
{
self.truck = [[TruckViewController alloc] init];
self.driver = [[DriverViewController alloc] init];
self.server = [[ServerViewController alloc] init];
if ([segue.identifier isEqualToString:@"segueToDriver"]) {
[self.truck addObserver:self.driver
forKeyPath:@"currentSpeedOfTheTruck"
options:NSKeyValueObservingOptionNew
context:NULL];
self.truck.currentSpeedOfTheTruck = [self.textFieldCurrenSpeed 
text];
NSLog(@"prepareForSegue: %@", self.truck.currentSpeedOfTheTruck);
}
if ([segue.identifier isEqualToString:@"segueToServer"]) {
[self.truck addObserver:self.server
forKeyPath:@"currentSpeedOfTheTruck"
options:NSKeyValueObservingOptionNew
context:NULL];
self.truck.currentSpeedOfTheTruck = [self.textFieldCurrenSpeed 
text];
NSLog(@"text entered: %@", self.truck.currentSpeedOfTheTruck);
}
}
- (void)dealloc
{
[self.truck removeObserver:self.driver 
forKeyPath:@"currentSpeedOfTheTruck"];
[self.truck removeObserver:self.server    
forKeyPath:@"currentSpeedOfTheTruck"];
}

司机.m

#import "DriverViewController.h"
@interface DriverViewController ()
@property (strong, nonatomic) IBOutlet UITextField   
*textFieldCurrentSpeed;
@end

-(void) observeValueForKeyPath:(NSString *)keyPath
ofObject:(id)object
change:(NSDictionary<NSKeyValueChangeKey,id> 
*)change
context:(void *)context {
if ([keyPath isEqualToString:@"currentSpeedOfTheTruck"]) {
NSLog(@"DriverViewController->currentSpeedOfTheTruck: %@",
[object valueForKey:keyPath]);
NSLog(@"DriverViewController->currentSpeedOfTheTruck: %@",
[change objectForKey:NSKeyValueChangeNewKey]);
self.receivedCurrentSpeed = [change   
objectForKey:NSKeyValueChangeNewKey];
[self.textFieldCurrentSpeed setText:self.receivedCurrentSpeed];
}
}

- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view.
NSLog(@"DriverViewController->viewDidLoad");
[self.textFieldCurrentSpeed setText:self.receivedCurrentSpeed];
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}

日志输出

2017-08-13 19:53:55.293 KVC-1[91529:2346883] DriverViewController-  
>currentSpeedOfTheTruck: 45
2017-08-13 19:53:55.294 KVC-1[91529:2346883] DriverViewController- 
>currentSpeedOfTheTruck: 45
2017-08-13 19:53:55.294 KVC-1[91529:2346883] prepareForSegue: 45

问题出在这些代码行上

self.truck = [[TruckViewController alloc] init];
self.driver = [[DriverViewController alloc] init];
self.server = [[ServerViewController alloc] init];

由于创建另一个对象而不是一个对象是在准备 segue 之前创建的,因此您应该使用segue.destinationController来传输值

将上面的代码行更改为

self.truck = (TruckViewController *) segue.destinationViewController;

对应于所有视图控制器。

  1. 您似乎正在-viewDidLoad而不是其他任何地方设置textFieldCurrentSpeed的文本内容,因此加载视图后它永远不会更改也就不足为奇了。

  2. 使用-observeValueForKeyPath:object:change:context:的模式不正确。你需要使用上下文变量,检查它,如果不匹配,调用super的实现。请参阅:https://developer.apple.com/library/content/documentation/Cocoa/Conceptual/KeyValueObserving/Articles/KVOBasics.html

有两个错误:

  1. truck中,您添加了观察者driver,但随后立即将其删除,因此在driver中您无法收到有关currentSpeedOfTheTruck的值更改的通知。 当您不需要观察器值更改时,但必须在driver dealloc之前将其删除。
  2. 当你收到currentSpeedOfTheTruck通知时,你只设置receivedCurrentSpeed的值,而不是self.textFieldCurrentSpeed.text,所以self.textFieldCurrentSpeedtext是空的。 将[self.textFieldCurrentSpeed setText:receivedCurrentSpeed]移动到功能observeValueForKeyPath:或覆盖receivedCurrentSpeedsetter

卡车.m

- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {    
if ([segue.identifier isEqualToString:@"segueToServer"]) {
if ([segue.destinationViewController isKindOfClass:[DriverViewController class]]) {
((DriverViewController *)segue.destinationViewController).sourceViewController = self;
[self addObserver:segue.destinationViewController forKeyPath:@"currentSpeedOfTheTruck" options:NSKeyValueObservingOptionNew context:nil];
}
}
}

司机.h

@property (nonatomic, weak) TrunkViewController *sourceViewController;

司机.m

- (void)dealloc {
[self.sourceViewController removeObserver:self forKeyPath:@"currentSpeedOfTheTruck"];
}
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context {
if ([keyPath isEqualToString:@"currentSpeedOfTheTruck"]) {
id newValue = [change objectForKey:NSKeyValueChangeNewKey];
if ([newValue isKindOfClass:NSString.class]) {
self.receivedCurrentSpeed = newValue
[self.textFieldCurrentSpeed setText:self.receivedCurrentSpeed];
}
} else {
[super observeValueForKeyPath:keyPath ofObject:object change:change context:context];
}
}

最新更新