2017-08-11 15 views
7

Uczę się jak używać KVO. Stworzyłem dwie klasy, Truck and Driver, jak pokazano poniżej.Jak przekazywać wartości za pomocą KVO?

klasa Truck ma pole tekstowe i przycisk, tekst powinien zawierać aktualną prędkość ciężarówki, a po naciśnięciu przycisku należy wywołać prepareForSegue i zawiera on kod zamieszczony poniżej.

Klasa Driver zawiera pole tekstowe, które należy wypełnić prędkością wózka. prędkość wózka w klasie Truck zostanie przekazana do pola tekstowego w klasie Driver przez KVO, jak pokazano w kodzie.

Problem jaki mam lub co próbuję zrobić to, gdy użytkownik wejdzie w prędkość ciężarówki w klasie Ciężarówka i naciśnie przycisk, chcę wyświetlić prędkość ciężarówki wprowadzoną w polu tekstowym w klasie Kierowca przez KVO

wynikiem jestem coraz według kodu zamieszczonych poniżej, pustym polu tekstowym w klasie sterowników

proszę dać mi znać, dlaczego TextField w klasie kierowcy jest pusty. a jak mam przekazać wartość prędkości wózka z klasy do klasy Truck kierowcy przez KVO

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

wyjściowego dziennika:

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 
+0

Co to jest wyjście dzienników? –

+0

@ AminNegm-Awad zobacz dane wyjściowe dziennika opublikowane – user2121

Odpowiedz

1
  1. Wydaje się, że jesteś ustawienie zawartości tekstowej textFieldCurrentSpeed w -viewDidLoad i nigdzie indziej, więc nie jest zaskakujące, że nigdy się nie zmienia po widok jest załadowany.

  2. Wzór użycia -observeValueForKeyPath:object:change:context: jest niepoprawny. Musisz użyć zmiennej kontekstowej, sprawdź to i zadzwoń do super-implementacji, jeśli nie pasuje. Zobacz: https://developer.apple.com/library/content/documentation/Cocoa/Conceptual/KeyValueObserving/Articles/KVOBasics.html

1

Jest dwa błędem:

  1. W truck dodać obserwatora driver, ale wtedy usuwane natychmiast, więc w driver nie można odbierać powiadomić o zmianie wartości dla currentSpeedOfTheTruck . usuń go, gdy nie potrzebujesz zmian wartości obserwatora, ale musisz przed driver dealloc.
  2. Gdy otrzymasz powiadomienie o currentSpeedOfTheTruck, ustawiasz tylko wartość dla receivedCurrentSpeed, a nie self.textFieldCurrentSpeed.text, więc text z self.textFieldCurrentSpeed jest puste. Przenieś [self.textFieldCurrentSpeed setText:receivedCurrentSpeed] do func observeValueForKeyPath: lub nadpisać setter z receivedCurrentSpeed

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

sterownik.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]; 
    } 
} 
+0

umieściłem [self.textFieldCurrentSpeed ​​setText: self.receivedCurrentSpeed]; w środku observalueforkey, ale nic się nie zmieniło. również próbowałem usunąć obserwatora gdzie indziej, ale nie mogłem, ponieważ muszę ogłosić wystąpienie klasy TrcuckViewController na całym świecie, i nie wiem jak to zrobić .. czy mógłbyś mi pomóc – user2121

+0

@ user2121 Przepraszam Nie zauważyłem twojego komentarza, zaktualizowałem odpowiedź, mam nadzieję, że ci pomoże. –

4

Problem jest z tych wierszy kodu

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

ponieważ twój tworząc inny obiekt niż jeden jest tworzony przed przygotowaniem do segue, należy użyj segue.destinationController, aby przenieść wartości

Zmień powyższy wiersz kodu na

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

Stosownie do wszystkich kontrolerów ViewController.

+0

, ale chcę przekazać wartość za pomocą KVO jako stan din. pytanie – user2121

+1

KVO to wzór obserwatora, nie przekazujesz wartości za pomocą KVO, otrzymujesz zmiany wartości za jego pomocą. Ważne jest, aby zrozumieć. Odpowiedź jest poprawna. Utworzono nowe wystąpienie TruckViewController, ale nie jest ono wyświetlane w interfejsie użytkownika i dlatego pole tekstowe jest puste. Wypróbuj rozwiązanie w tej odpowiedzi. –

Powiązane problemy