【问题标题】:Key Value Observing context not work键值观察上下文不起作用
【发布时间】:2016-03-17 10:02:50
【问题描述】:

在 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 *)contextmethod 中的 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 类:

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 的新旧值未显示。可以看到 context 和 bankContext 的值不相等,如下图所示:

有人知道吗?

【问题讨论】:

  • 如果你使用一个静态类,那么这个类如果有效地减少为一个单例。为什么要这样限制课程?
  • 本文建议nshipster.com/key-value-observing 。作为令牌。如果我不关心不同的实例,只要同一个类,我认为就可以了。关键是为什么contex和bankContext不相等。
  • 啊,好吧——我的错。我收回了:)

标签: objective-c key-value-observing


【解决方案1】:

原因是有两个bankContexts。在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 相互导入)。

【讨论】:

  • 你说的是对的!使用 bankContext = &bankContext 的目的是作为某个类的标记 (nshipster.com/key-value-observing)。为此,我认为可能使用if(object isKindOfClass:[Bank class]])if([context == bankContext) 没有额外的bankContext 变量声明更好。
  • 我建议您继续使用 NSHipster 文章中建议的上下文指针。您需要了解有关 C 中变量存储的更多信息,才能将其正确应用于您的情况。
  • 感谢您的建议,我已经看到了静态和外部之间的区别。是不是没有必要把上下文指针声明为一个标记来识别情况?由于我的知识,我没有看到其他优势。
  • 这不是绝对必要的,但会更健壮,因为超类或子类(甚至可能是其他对象)也可能会设置观察结果,如果您只检查对象和关键路径,可能会产生干扰。
猜你喜欢
  • 1970-01-01
  • 2012-08-08
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-03-29
  • 2012-10-29
相关资源
最近更新 更多