关键价值观察背景不起作用

时间:2016-03-17 10:02:51

标签: objective-c key-value-observing

在Objective-C中,当使用Key-Value Observing时,我有一个带有accountDomestic属性和person属性的Bank类。添加人员以观察accountDomestic属性。我在Bank类中有static void *bankContext = & bankContext作为其上下文。但是,在我更改accountDomestic属性后,由于Person中的-(void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSString *,id> *)change context:(void *)context方法中的上下文和bankContext不匹配,旧值和新值未正确显示。

代码如下,首先是银行类:

Bank.h

#import <Foundation/Foundation.h>
#import "Person.h"

static void * const bankContext = &bankContext;
@class Person;

@interface Bank : NSObject
@property (nonatomic, strong) NSNumber* accountDomestic;
@property (nonatomic, strong) Person* person;
-(instancetype)initWithPerson:(Person *)person;
@end



Bank.m

@implementation
-(instancetype)initWithPerson:(Person *)person{
    if(self = [super init]){
        _person = person;
        [self addObserver:_person 
               forKeyPath:NSStringFromSelector(@selector(accountDomestic)) 
                  options:NSKeyValueObservingOptionOld|NSKeyValueObservingOptionNew
                  context:bankContext];
}
    return self;
}

-(void)dealloc{
    [self removeObserver:_person forKeyPath:NSStringFromSelector(@selector(accountDomestic))];
}

@end

然后是人类:

Person.h

#import <Foundation/Foundation.h>
#import "Bank.h"
@interface Person : NSObject
@end


Person.m

#import "Person.h"
@implementation Person

-(void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSString *,id> *)change context:(void *)context{
    NSLog(@"context: %p",context);
    NSLog(@"bankContext: %p",bankContext);
    if(context == bankContext){
        if([keyPath isEqualToString:NSStringFromSelector(@selector(accountDomestic))]){
            NSString *oldValue = change[NSKeyValueChangeOldKey];
            NSString *newValue = change[NSKeyValueChangeNewKey];
            NSLog(@"--------------------------");
            NSLog(@"accountDomestic old value: %@", oldValue);
            NSLog(@"accountDomestic new value: %@", newValue);
        }
    }
}

@end

最后是ViewController类

ViewController.h

#import <UIKit/UIKit.h>
@interface ViewController : UIViewController
@end


ViewController.m

#import "ViewController.h"
#import "Bank.h"
#import "Person.h"
@interface ViewController ()
@property (nonatomic, strong) Bank *bank;
@property (nonatomic, strong) Person *person;
@property (nonatomic, strong) NSNumber *delta;
@end

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    self.person = [[Person alloc] init];
    self.delta = @10;
    self.bank = [[Bank alloc] initWithPerson:self.person];
}

- (IBAction)accountDomesticIncreaseButtonDidTouch:(id)sender {
    self.bank.accountDomestic = self.delta;
    int temp = [self.delta intValue];
    temp += 10;
    self.delta = [NSNumber numberWithInt:temp];
}
@end

单击按钮后,accountDomestic的新旧值未显示。您可以看到上下文和bankContext值不等于下图所示:

enter image description here

有没有人知道这件事?

1 个答案:

答案 0 :(得分:2)

原因是有两个bankContext。在Bank.h中,您有

static void * const bankContext = &bankContext;

此文件随后包含在Bank.mPerson.m中,因此两个文件(编译单元)都定义了一个指针bankContext,标记为static因此生成否外部链接(所以你可以有两个同名)。

最直接的解决方案是确保只有一个bankContext。在Bank.h

extern void * const bankContext;

Bank.m

void * const bankContext = &bankContext;

More about static and extern.

那就是说,我认为重组代码会更好,所以这不是必需的。你的责任设置让我很谨慎(一个对象告诉另一个成为一个观察者),我很惊讶它正确编译,因为似乎有循环导入(Bank.hPerson.h相互导入)。