【问题标题】:How to pass values using KVO?如何使用 KVO 传递值?
【发布时间】:2018-01-20 08:09:53
【问题描述】:

我正在学习如何使用 KVO。我创建了两个类,Truck 和 Driver,如下所示。

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

Driver 类包含一个应填写卡车速度的文本字段。 Truck 类中的卡车速度将通过 KVO 传递给 Driver 类中的文本字段,如代码所示。

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

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

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

Truck.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"];
}

Driver.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

【问题讨论】:

  • 日志的输出是什么?
  • @AminNegm-Awad 请查看发布的日志输出

标签: ios objective-c uistoryboardsegue key-value-observing kvc


【解决方案1】:

问题在于这些代码行

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

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

将上面的代码行改为

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

根据所有视图控制器。

【讨论】:

  • 但我想使用 KVO 作为状态 din 传递值。问题
  • KVO 是一种观察者模式,您不是使用 KVO 传递值,而是使用它接收值更改。了解这一点很重要。答案是正确的。您已经创建了一个新的 TruckViewController 实例,但它没有显示在 UI 上,这就是您的 textField 为空的原因。尝试此答案中的解决方案。
【解决方案2】:

有两个错误:

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

卡车.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;

Driver.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];
    }
}

【讨论】:

  • 我放置了 [self.textFieldCurrentSpeed setText:self.receivedCurrentSpeed];在 observevalueforkey 内,但没有任何改变。我也尝试在其他地方删除观察者,但我不能,因为我必须全局声明 TrcuckViewController 类的实例,而且我不知道该怎么做..请你帮帮我
  • @user2121 很抱歉我没有注意到你的评论,我已经更新了答案,希望对你有所帮助。
【解决方案3】:
  1. 看来您是在-viewDidLoad 中设置textFieldCurrentSpeed 的文本内容,而其他任何地方都没有,因此加载视图后它永远不会改变也就不足为奇了。

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2013-06-05
    • 2016-07-28
    • 1970-01-01
    • 2023-03-21
    • 1970-01-01
    • 1970-01-01
    • 2011-09-10
    相关资源
    最近更新 更多